题目
交互题,首先给定一个n(n<=1e5),并想好一个数x(1<=x<=n),
你需要在不超过10000次操作中,猜出这个数x,
集合S里初始有{1,...,n}共n个数,操作分三种,
①A a,询问当前集合中a的倍数有多少个
②B a(a>1),询问当前集合中a的倍数有多少个,并删掉a的倍数,特别地,x不会被删掉
③C a,猜出当前的数x的值为a,只能执行一次,程序会被结束
思路来源
codeforces群里口胡
题解
sum实时统计当前还有多少数没有被删,
预处理所有素数,9592个,考虑在这上面做文章,
首先,考虑<=sqrt(n)的素数,
小于317的素数也就65个,
对其每个素数p,询问一次B,删掉p的所有倍数,
再从p开始,p^2,p^3,不断往上询问A,
如果出现当前p^k非零,说明x是p^k的倍数,没有在删p的倍数的操作中被删掉
考虑到2^17>1e5,
这部分最多会被B65次,A65次,A如果命中,最多再询问17次
一个很重要的事实是,大于sqrt(n)的素因子只能在x里出现一次,
①如果ans>sqrt(n),说明ans不存在大于sqrt(n)的素因子,直接回答答案
②ans<sqrt(n),考虑>sqrt(n)的9527个素数,
(1)如果ans!=1,
说明x已经被小素数p删过,但是没删掉,
这样在遍历大素数q的时候,会出现p*q的存在性与预想不一致的情况,遍历即可找出
(2)如果ans==1,
说明ans就是一个大素数,考虑对其按根号分块,约98个一块
对每个块内的素数先逐个B删除,再询问一次1,
如果数量与预想不一致,说明x保留在该块内,再对该块内逐个A询问找出即可
由于+17和分块对应不同的两种情况,
所以最后询问次数上限,为9592+98(询问1)+98(check块内每个)+65+65
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int n,pr[N],c,sum;
bool vis[N],del[N];
int ask(char x,ll y){
printf("%c %lld\n",x,y);
fflush(stdout);
if(x=='C')return 0;
int v;
scanf("%d",&v);
return v;
}
void Del(int x){
for(int i=x;i<=n;i+=x){
if(!del[i]){
sum--;
del[i]=1;
}
}
}
int cal(int x){
int tot=0;
for(int i=x;i<=n;i+=x){
tot+=(!del[i]);
}
return tot;
}
int main(){
scanf("%d",&n);
sum=n;
for(int i=2;i<=n;++i){
if(!vis[i]){
pr[++c]=i;
}
for(ll j=1ll*i*i;j<=n;j+=i){
vis[j]=1;
}
}
int ans=1,pos;
for(int i=1;i<=c && 1ll*pr[i]*pr[i]<=n;++i){
int num=ask('B',pr[i]);
Del(pr[i]);
for(ll v=pr[i];v<=n;v*=pr[i]){
int now=ask('A',v);
if(now){
ans*=pr[i];
}
else{
break;
}
}
pos=i;
}
int sq=sqrt(n);
if(ans>sq){
ask('C',ans);
}
else{
if(ans!=1){
for(int i=pos+1;i<=c;++i){
int now=ask('A',pr[i]),tot=cal(pr[i]);
if(now!=tot){
ans*=pr[i];
break;
}
}
ask('C',ans);
}
else{//ans=一个大素数
int blk=sqrt(c-pos);
for(int l=pos+1;l<=c;l+=blk){
int r=min(l+blk-1,c);
for(int i=l;i<=r;++i){
int now=ask('B',pr[i]);
Del(pr[i]);
}
int num=ask('A',1);
if(num!=sum){
for(int i=l;i<=r;++i){
int now=ask('A',pr[i]),tot=cal(pr[i]);
if(now!=tot){
ans*=pr[i];
break;
}
}
break;
}
}
ask('C',ans);
}
}
return 0;
}