嘘~ 正在从服务器偷取页面 . . .

CF1406E Deleting Numbers 题解


CF1406E Deleting Numbers 题解

题目链接:Deleting Numbers

题意

这是一道交互题。

已知 \(n\), 有一个未知数 \(x\) \((1\le x\le n)\),你需要求出 \(x\) 的值。

一开始,你有一个集合 \(S=\{x\mid x\le n,x\in \mathbb{N^+}\}\)

你可以对这个集合执行不超过 \(10000\) 次 A、B、C 操作(总和不超过)。

  1. A \(a\),表示求出 \(S\)\(a\) 的倍数的个数 \((1\le a\le n)\)

  2. B \(a\),表示求出 \(S\)\(a\) 的倍数的个数,

    并将这些 \(a\) 的倍数从 \(S\) 中删去(\(x\) 是不会被删掉的) \((2\le a\le n)\)

  3. C \(a\),表示你知道了 \(x=a\) \((1\le a\le n)\)

所有的 \(a\) 均为整数。数据范围 \(1 \le n \le 10^5\)

由于本题和整除有关,所以很容易想到特殊考虑质因子。

假设我们知道 \(x\) 的所有质因子,那么可以通过枚举幂次,然后反复询问 \(\mathrm{A}\ p^k\) 以得到答案。

现在考虑对于一个质数 \(p\) 询问一次 \(\mathrm{B}\ p\) ,同时我们也维护一个集合,表示会删除 \(x\) 时,还剩哪些数

若得到的答案和我们维护得到的答案不同,则说明 \(x\)\(p\) 这个质因子,暴力询问幂次即可。

通过这样的方法,我们可以找到除了最小质因子以外的全部质因子(因为最小质因子得到的答案是相同的)

考虑分块来找到这个最小质因子。记 \(m = \pi(n)\) ,即质数的个数。

每隔 \(\sqrt{m}\) 个质数做一次 \(\mathrm{A}\ 1\) 询问,检查最小质因子是否在当前块内。

如果在,则暴力扫描块内的每个质数 \(p\) ,每次询问 \(\mathrm{A}\ p\) ,即可得到最小质因子,进而确定 \(x\)

时间复杂度 \(\mathcal{O}(n \log n)\) ,总操作次数为 \(m + 2\sqrt{m} + \log n\)

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x, int y) { x < y ? x = y : 0; }
void down(int &x, int y) { x > y ? x = y : 0; }
#define rep(i, a, b) for(int i = (a), i##END = (b); i <= i##END; i++)
#define Rep(i, a, b) for(int i = (a), i##END = (b); i >= i##END; i--)
#define N ((int)(1e5 + 15))

char ck[N], vis[N]; int pcnt, p[N];
void init(int n)
{
    rep(i, 2, n)
    {
        if(!ck[i]) { p[++pcnt] = i; }
        rep(j, 1, pcnt)
        {
            if(i * p[j] > n) break;
            ck[i * p[j]] = true; if(i % p[j] == 0) break;
        }
    }
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    int n, x; cin >> n; init(n);
    int m = sqrt(pcnt), tot = n, ans = 1; bool ok = false;
    rep(i, 1, pcnt)
    {
        if(i >= m && ans * p[i - m + 1] > n) break;
        cout << "B " << p[i] << endl;
        int cnt = 0;
        for(int j = p[i]; j <= n; j += p[i])
            if(!vis[j]) { ++cnt, --tot; vis[j] = true; }
        cin >> x;
        if(x != cnt)
        {
            for(int k = p[i]; k <= n; k *= p[i])
            {
                cout << "A " << k << endl; cin >> x;
                if(x) ans *= p[i]; else break;
            }
        }
        if((i == pcnt || i % m == 0) && !ok)
        {
            cout << "A 1" << endl; cin >> x;
            if(x != tot)
            {
                rep(j, i - m + 1, i)
                {
                    for(int k = p[j]; k <= n; k *= p[j])
                    {
                        cout << "A " << k << endl; cin >> x;
                        if(x) { ans *= p[j], ok = true; } else break;
                    }
                    if(ok) break;
                }
            }
        }
    }
    cout << "C " << ans << endl;
    return 0;
}

参考文献

[1] https://www.luogu.com.cn/article/249mao5g


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录