CF1406E. Deleting Numbers

题目大意

交互题

有一个[1,n]中的数x,要求在10000次操作内找出,有一个集合{1...n}和三种操作

A:询问集合内a的倍数个数

B:询问集合内a(a>=2)的倍数个数,同时删掉除x外所有a的倍数

C:回答

题解

在被Good Bye2019打出心里阴影后九个月没打了尝试上分

由于10000>=9592(质数个数)+171(<=√n的质数的最大指数和)+100(√9592)*2,所以做法一目了然

简单的思路:删掉所有质数,之后依次确定每个质数的指数

这样次数至少是个数*2,但是由于>√n的质数只有最多一个,所以可以先求出这个质数,把>√n的每100个分块,删完之后再查询a=1,这样可以用200次额外操作解决

<=√n的全部删掉后依次确定即可

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define ll long long
//#define file
using namespace std;

int p[100001],n,s,i,j,k,l,len,sum,ls,S,s2,ans;
bool f[100001];

void init()
{
	fo(i,2,n)
	{
		if (!f[i]) p[++len]=i;
		fo(j,1,len)
		if (1ll*i*p[j]<=n)
		{
			f[i*p[j]]=1;
			if (!(i%p[j])) break;
		}
		else break;
	}
}

void ask(char ch,int s) {printf("%c %d
",ch,s);fflush(stdout);}
void del(int t) {sum-=f[t];f[t]=0;}

void find()
{
	fo(l,1,len)
	if (p[l]>s) break;
	
	S=1;
	k=0;
	ls=l-1;
	fo(i,l,len)
	{
		++k;
		ask('B',p[i]);
		scanf("%d",&s2);
		for (j=p[i]; j<=n; j+=p[i]) del(j);
		
		if (k==100 || i==len)
		{
			ask('A',1);
			scanf("%d",&s2);
			if (s2!=sum)
			{
				fo(j,ls+1,i)
				{
					ask('A',p[j]);
					scanf("%d",&s2);
					if (s2==1) {S=p[j];return;}
				}
			}
			k=0,ls=i;
		}
	}
}

int main()
{
	scanf("%d",&n);s=floor(sqrt(n));
	init();
	fo(i,1,n) f[i]=1;sum=n;
	
	find();
	fo(i,1,len)
	if (f[p[i]])
	{
		ask('B',p[i]);
		scanf("%d",&s2);
		for (j=p[i]; j<=n; j+=p[i]) del(j);
	}
	
	ans=S;
	fo(i,1,len)
	if (p[i]<=s)
	{
		j=p[i],k=1;
		while (j<=n)
		{
			ask('A',j);
			scanf("%d",&s2);
			if (s2) ans*=p[i];
			else break;
			
			if (j<=n/p[i]) j*=p[i];
			else break;
		}
	}
	ask('C',ans);
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}
原文地址:https://www.cnblogs.com/gmh77/p/13659973.html