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;
}
posted @ 2022-05-08 19:40  Plozia  阅读(34)  评论(0编辑  收藏  举报