1. 程式人生 > 其它 >CF1406E Deleting Numbers 題解

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;
}