CF1406E Deleting Numbers 题解
一道 Idea 题,但是做过两道类似寿司晚宴的我还是没能想出这道题……
一个显然的思路是先枚举所有质数用 B 操作筛掉合数,然后用 A 操作知道有哪些质因子,枚举这些质因子的次幂得到这个数,但 100000 以内的质数个数是 9592,先筛合数再用 A 操作都已经超出限制了。
考虑按照 \(\sqrt{n}\) 划分,首先线筛出所有的质数,然后利用所有小于等于 \(\sqrt{n}\) 的质数筛掉所有合数,同时枚举次幂以得知 \(x\) 小于等于 \(\sqrt{n}\) 的质因子及其次幂,将这个结果记作 \(s\)(\(s\) 初始化为 1)。
如果 \(s>1\) 说明 \(x\) 是个合数并且可能有一个大于 \(\sqrt{n}\) 的质因数,此时用 A/B 操作枚举这些质数看一眼哪个返回值是 2 就知道最大质因数了。
如果 \(s=1\) 说明 \(x\) 是 1 或者是大于 \(\sqrt{n}\) 的质数,考虑分块,每 100 个质数分成一块,对每一块首先利用 B 操作删掉质数,然后使用 A 1
可以得知这一块删了多少个数,便可得知 \(s\) 是不是在这一块内,如果在就暴力用 A/B 操作查询即可。
几个注意点:
- 注意 \(n=1,x=1\) 这样的询问。
- 任意时刻你向交互库输出的数不能大于 \(n\)。
GitHub:CodeBase-of-Plozia
Code:
/*
========= Plozia =========
Author:Plozia
Problem:CF1406E Deleting Numbers
Date:2022/5/8
========= Plozia =========
*/
#include <bits/stdc++.h>
typedef long long LL;
const int MAXN = 1e5 + 5;
int n, Prime[MAXN], cntPrime, p, ans = 1;
bool book[MAXN];
int Read()
{
int sum = 0, fh = 1; char ch = getchar();
for (; ch < '0' || ch > '9'; ch = getchar()) fh -= (ch == '-') << 1;
for (; ch >= '0' && ch <= '9'; ch = getchar()) sum = sum * 10 + (ch ^ 48);
return sum * fh;
}
int Max(int fir, int sec) { return (fir > sec) ? fir : sec; }
int Min(int fir, int sec) { return (fir < sec) ? fir : sec; }
void init()
{
for (int i = 2; i <= n; ++i)
{
if (!book[i]) Prime[++cntPrime] = i;
for (int j = 1; j <= cntPrime; ++j)
{
if (i * Prime[j] > n) break ;
book[i * Prime[j]] = 1;
if (i % Prime[j] == 0) break ;
}
}
}
int optA(int x) { printf("A %d\n", x); fflush(stdout); return Read(); }
int optB(int x) { printf("B %d\n", x); fflush(stdout); return Read(); }
int main()
{
n = Read(); init(); for (p = 1; p * p <= n; ++p) ; --p; int i = 1;
for (i = 1; Prime[i] <= p && i <= cntPrime; ++i)
{
optB(Prime[i]);
int tmp = Prime[i];
if (optA(Prime[i]) == 0) continue ;
while (tmp * Prime[i] <= n) { if (optA(tmp * Prime[i]) == 0) break ; tmp *= Prime[i]; }
ans = ans * tmp;
}
if (ans != 1)
{
for (; i <= cntPrime; ++i)
if (optA(Prime[i]) == 2) { ans *= Prime[i]; break ; }
}
else
{
int Last = i, Remain = optA(1);
for(; i <= cntPrime; ++i)
{
optB(Prime[i]);
if (i - Last + 1 == 100 || i == cntPrime)
{
int tmp = optA(1);
if (Remain - tmp == i - Last + 1) { Last = i + 1; Remain = tmp; continue ; }
for (int j = Last; j <= i; ++j)
{
if (optA(Prime[j]) == 1) { ans = Prime[j]; break ; }
}
break ;
}
}
}
printf("C %d\n", ans); fflush(stdout); return 0;
}