CF1406E Deleting Numbers 題解
阿新 • • 發佈:2022-05-08
一道 Idea 題,但是做過兩道類似壽司晚宴的我還是沒能想出這道題……
一個顯然的思路是先列舉所有質數用 B 操作篩掉合數,然後用 A 操作知道有哪些質因子,列舉這些質因子的次冪得到這個數,但 100000 以內的質數個數是 9592,先篩合數再用 A 操作都已經超出限制了。
考慮按照 \(\sqrt{n}\) 劃分,首先線篩出所有的質數,然後利用所有小於等於 \(\sqrt{n}\) 的質數篩掉所有合數,同時列舉次冪以得知 \(x\) 小於等於 \(\sqrt{n}\) 的質因子及其次冪,將這個結果記作 \(s\)(\(s\) 初始化為 1)。
如果 \(s>1\) 說明 \(x\) 是個合數並且可能
如果 \(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; }