Codeforces Round #670 (Div. 2) E. Deleting Numbers(交互,素数构造)

题意:
给定序列 [ 1 , n ] [1,n] [1,n],用给定的合法操作猜出 x x x
有三种操作

  • A a:问含a因子的数字的个数
  • B a:问含a因子的数字的个数,之后把除了答案的所有含a因子的数字从序列删除。
  • C a:确定答案是a
    思路:
    讲道理应该是能操着 1 0 4 10^4 104这个操作数过去的。但是本人代码太不美观了导致从1wa到了11,还有好多是因为操作数过量,希望人没事。wa了一天以后整理了一下思路如下:
    乱涂的,在分块找大素数那边后来用二维表示感觉对我这种zz更合适一些
    正经思路:
  • 有一个最初的想法就是对于每个素数都先 B B B p r i m e i prime_i primei一遍,然后再 A A A p r i m e i prime_i primei看答案是不是 0 0 0,如果不是就说明含有这个素数作为因子。之后再一遍遍 A A A p r i m e i k prime_i^k primeik询问上去直到答案等于0就可。仔细思考一下, 1 0 5 10^5 105的素数数量是 9592 9592 9592,光是AB各两边遍历所有的素数就超了兄弟。
  • 再想想再想想,发现其实对于每次A的询问可以分段进行。
  • S t e p 1 : Step1: Step1
    1. 每次都假设这一段里面没有我要找的 x x x,遍历段内进行 B B B p r i m e i prime_i primei的操作。
    1. 我们要做的就是维护一个 c u r cur cur(假设段内无 x x x,余下的数字总数),然后在每块的末尾进行 A A A 1 1 1的询问,看实际的答案和假定的 c u r cur cur是否相等。
    1. 如果相等就继续下一块,不相等就直接遍历块内所有素数,进行 A A A p r i m e i prime_i primei的询问,如果不等于0就必然含有这个因子。之后要做的就是 l o g n log_n logn的指数遍历就好。
  • 问题又来了:咋维护啊?你也不知道除完以后去了多少个啊哥哥??要容斥定理来吗啊这
  • 再想想再想想,如果我们的序列中只含有素数那是不是就问题会简单好多?每次遍历段内进行 B B B p r i m e i prime_i primei的操作之后只要进行 c u r − − cur-- cur就很爽啊?那要咋做到?筛鸭,不是有个啥子定理表明 N \sqrt{N} N 就能把 N N N的所有的合数给整了,只剩下素数咩?那就好办了啊爹
  • S t e p 2 : Step2: Step2:
    1. N N N N \sqrt{N} N 分成两部分,小的那一部分包括了我们的小素数,大的那一部分包括了大素数。
    1. 首先就是用小素数进行筛,让原数列中只含有大素数、1(也可能有 x x x)。这里小素数的个数最多大概是65(?)。在这一步中可以对于 x x x是否包含小素数进行询问试探(就是最初的想法实践一下)
    1. 然后产生的答案就可能有两种情况:
      • 第一种是已经确定有小素数了,如果他是一个大素数与小素数的合数,那他必然保留在大素数序列之外,要做的就是进行 A A A p r i m e i prime_i primei的询问,看答案有没有等于 2 2 2的。
      • 第二种是没有小素数,那他只可能包含大素数的一次方,因为筛过之后数列里面只剩下大素数了,就用刚刚说的,每次遍历段内进行 B B B p r i m e i prime_i primei的操作之后只要进行 c u r − − cur-- cur。假设大素数的个数是 G G G段内的大素数个数是 G G G,那么这样的操作我们大概需要多花费 S + G S S+\frac{G}{S} S+SG,对于 S S S的确定就很明显了,对勾函数的最低点 G \sqrt{G} G (最大好像是97?)

最后大概是9800左右的操作?
以上是口胡^^

代码:

int v[maxn], prime[maxn];//v存质数,vis判断是不是质数
int primes(int n) {
    
    
	int m = 0;
	for (int i = 2; i <= n; i++) {
    
    
		if (v[i] == 0) {
    
    //i是质数
			v[i] = i; prime[++m] = i;
		}
		for (int j = 1; j <= m; j++) {
    
    
			if (prime[j] > v[i] || prime[j] > n / i)break;
			v[i*prime[j]] = prime[j];
		}
	}
	return m;
}
int main()
{
    
    
	int n, m, ans, M, g, start;
	int t;
	int tt, tot, temp, cur;
	tot = 0;
	cur = 0;
	g = 0;
	start = 0;
	M = primes(maxn);
	ans = 1;

	//cout << M - tot << endl;
	//cout << tot << endl;*/
	sci(n);

	if (n == 1) {
    
    
		printf("C 1\n");
		return 0;
	}
	for (int i = 1; prime[i] <= n; i++) {
    
    
		//if (prime[i] == 99874/2)cout << 1 << endl;
		cur++;
		if ((LL)(prime[i]) * (LL)(prime[i]) > (LL)(n))g++;
		else start = i;
	}
	M = cur;
	//cout << (int)(sqrt(g)) << endl;
	for (int i = 1; prime[i] * prime[i] <= n; i++) {
    
    //寻找小素数(可能有多个次方)
		cur--;
		printf("B %d\n", prime[i]);
		fflush(stdout);
		sci(tt);
		printf("A %d\n", prime[i]);
		fflush(stdout);
		sci(tt);
		if (tt) {
    
    
			ans *= prime[i];
			temp = prime[i];
			while (temp*prime[i] <= n) {
    
    
				temp *= prime[i];
				//printf("B %d\n", temp);
				printf("A %d\n", temp);
				fflush(stdout);
				sci(tt);
				if (tt == 0)break;
				else ans *= prime[i];
			}
		}
	}
	int s = (int)(sqrt(g));
	int pos;
	if (ans == 1) {
    
    //只含大素数
		//lst = start + 1;
		for (int i = 0; i <= g / s - (g%s == 0); i++) {
    
    
			if (ans != 1)break;
			for (int j = 0; j < s; j++) {
    
    
				pos = start + i * s + j + 1;
				if (pos > M)continue;
				printf("B %d\n", prime[pos]);
				fflush(stdout);
				sci(tt);
				cur--;
			}
			printf("A 1\n");
			fflush(stdout);
			sci(tt);
			if (tt != cur + 1) {
    
    
				for (int j = 0; j < s; j++) {
    
    
					pos = start + i * s + j + 1;
					if (pos > M)continue;
					printf("A %d\n", prime[pos]);
					fflush(stdout);
					sci(tt);
					if (tt) {
    
    
						ans *= prime[pos];
					}
				}
			}
		}
	}
	else {
    
    //大素数,只可能一次方
		for (int i = start + 1; prime[i] <= n; i++) {
    
    
			//if (prime[i] * prime[i] <= n)continue;
			printf("A %d\n", prime[i]);
			fflush(stdout);
			sci(tt);
			if (tt == 2) {
    
    
				ans *= prime[i];
				break;
			}
		}
	}
	printf("C %d\n", ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44986601/article/details/108719264