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 操作(总和不超过)。
A \(a\),表示求出 \(S\) 中 \(a\) 的倍数的个数 \((1\le a\le n)\)
B \(a\),表示求出 \(S\) 中 \(a\) 的倍数的个数,
并将这些 \(a\) 的倍数从 \(S\) 中删去(\(x\) 是不会被删掉的) \((2\le a\le n)\)
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;
}
参考文献: