CF1406E Deleting Numbers

题目来源:Codeforces, CF1406E Deleting Numbers

题目大意

题目链接

交互题。

有一个未知的整数 (x) ((1leq xleq n)),你需要通过交互找出它。

初始时,交互库会告诉你 (n)

有一个集合 ({1,2,dots ,n})。你可以进行不超过 (10^4) 次操作。每次操作可以是如下三种之一:

  • ( ext{A }a):向交互库询问,当前集合里有多少数是 (a) 的倍数。
  • ( ext{B }a):向交互库询问,当前集合里有多少数是 (a) 的倍数。然后将所有 (a) 的倍数删去。特别地:(x) 将不会被删去,即使它是 (a) 的倍数。此操作必须保证 (a > 1)
  • ( ext{C }a):向交互库报告你找出的 (x)

请在规定操作次数内求出 (x)

数据范围:(1leq nleq 10^5)

本题题解

考虑一种暴力做法。枚举 (1dots n) 中每个质数 (p),再枚举 (p)(n) 以下的所有次幂 (p^k)。先用 ( ext{B}) 操作删除 (p^k) 的倍数,再用 ( ext{A}) 操作查询集合里是否仍有 (p^k) 的倍数。若有,说明 (x)(p^k) 的倍数。这样,我们可以知道每个质数在 (x) 里的最大次幂是多少,根据唯一分解定理,我们也就确定了 (x)

(pi(n))(1dots n) 中的质数数量,( au(n))(1dots n) 中的质数的幂的数量。打表发现,(pi(10^5)=9592, au(10^5)=9700)。上述做法,需要 (2 au(n)+1) 次操作(最后一次操作是报告答案),无法通过本题。

一个小优化是,对每个质数 (p),先用 ( ext{B}) 操作删除所有 (p) 的倍数,再依次询问所有次幂。操作次数优化为 (pi(n)+ au(n)+1),但仍无法通过本题。

有一个经典的技巧是,把质数分为 (leq sqrt{n}) 的“小质数”和 (> sqrt{n}) 的“大质数”。小质数总共只有 (pi(sqrt{n})) 个。而大质数在任何 (x) 里至多只有 (1) 个。

先用 (pi(sqrt{n})+ au(sqrt{n})leq 238) 次操作,求出 (x) 中所有小质因子及其次幂。设 (x) 的小质因子部分为 (x_{ ext{small}})。此时,集合里还剩下 (1)(x)、以及所有大质数。我们要确定 (x) 里还剩下的那 (1) 个大质因子是谁(或者根本没有大质因子)。

在前面的朴素做法里,我们实际对每个大质数用了 (2) 次询问,这样太多了。考虑减小这个次数。分两种情况:

  • 如果 (x_{ ext{small}} > 1):我们对每个大质数 (p),直接用 ( ext{A}) 操作询问 (p imes x_{ ext{small}})。如果结果为 (1),说明 (x) 就等于 (p imes x_{ ext{small}})(不然的话,这个数此时应该已经被删了);如果结果为 (0),说明 (p) 不是 (x) 的大质因子。这样,对每个大质因子只需要 (1) 次操作。找出大质因子所需的操作次数等于大质因子的数量,为:(pi(n)-pi(sqrt{n}))。加上小质数的部分,以及报告答案的操作,总次数为 (pi(sqrt{n})+ au(sqrt{n})+(pi(n)-pi(sqrt{n}))+1=pi(n)+ au(sqrt{n})+1leq 9766)
  • 如果 (x_{ ext{small}}=1):此时 (p imes x_{ ext{small}}) 就是大质数 (p) 本身,它本来就应该在集合里,所以直接询问是没有意义的。这种情况下,集合里只剩 (1) 和大质数(因为 (x) 本身也是 (1) 或大质数)。考虑大质数序列分块。每块里,先依次用 ( ext{B}) 操作将本块的大质数全部删除,然后用 ( ext{A}) 操作对 (1) 进行一次询问(也就是询问整个集合剩余的数的数量)。如果发现集合大小减少的量,少于我们删除的量,说明 (x) 就在本块里,我们枚举本块中的数,依次询问。这样,设块的大小为 (S),则找出大质数所需的操作次数为:(pi(n)-pi(sqrt{n})+lceilfrac{pi(n)-pi(sqrt{n})}{B} ceil+B)。取 (B = lfloorsqrt{pi(n)-pi(sqrt{n})} floor = 97) 时,这部分的最大操作次数为 (9723)。加上小质数的部分,以及报告答案的操作,最大总次数为 (9962)。可以通过本题。

参考代码

// problem: CF1406E
#include <bits/stdc++.h>
using namespace std;

#define pb push_back
#define mk make_pair
#define lob lower_bound
#define upb upper_bound
#define fi first
#define se second
#define SZ(x) ((int)(x).size())

typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;

template<typename T> inline void ckmax(T& x, T y) { x = (y > x ? y : x); }
template<typename T> inline void ckmin(T& x, T y) { x = (y < x ? y : x); }

const int MAXN = 1e5;
const int SQRT = 316;
const int BLOCK_SIZE = 97;

int ask(int x) {
	cout << "A " << x << endl;
	int res; cin >> res;
	return res;
}
int ask_and_del(int x) {
	cout << "B " << x << endl;
	int res; cin >> res;
	return res;
}
void report_ans(int x) {
	cout << "C " << x << endl;
}

int n, ans;
int p[MAXN + 5], cnt_p;
bool v[MAXN + 5];
void sieve(int lim) {
	for (int i = 2; i <= lim; ++i) {
		if (!v[i]) {
			p[++cnt_p] = i;
		}
		for (int j = 1; j <= cnt_p && p[j] * i <= lim; ++j) {
			v[i * p[j]] = 1;
			if (i % p[j] == 0) break;
		}
	}
}
int main() {
	cin >> n;
	sieve(n);
	ans = 1;
	// first part: 
	int second_part_start = cnt_p + 1;
	for (int i = 1; i <= cnt_p; ++i) {
		if (p[i] > SQRT) {
			second_part_start = i;
			break;
		}
		int res = ask_and_del(p[i]);
		if (!res) continue;
		int lastval = 0, flag = 0;
		for (ll j = p[i]; j <= n; j *= p[i]) {
			if (!ask(j)) {
				ans *= j / p[i];
				flag = 1;
				break;
			}
			lastval = j;
		}
		if (!flag) {
			ans *= lastval;
		}
	} // 238
	
	// second part:
	if (ans > 1) {
		for (int i = second_part_start; i <= cnt_p; ++i) {
			if ((ll)p[i] * ans > n)
				continue;
			if (ask(p[i] * ans)) {
				ans *= p[i];
				break;
			}
		} // 9765
		report_ans(ans);
	} else {
		// 分块
		for (int i = second_part_start; i <= cnt_p; i += BLOCK_SIZE) {
			int j = min(cnt_p, i + BLOCK_SIZE - 1);
			for (int k = i; k <= j; ++k) {
				ask_and_del(p[k]);
			}
			int res = ask(1);
			if (res > 1 + cnt_p - j) {
				assert(res == 1 + cnt_p - j + 1);
				for (int k = i; k <= j; ++k) {
					if (ask(p[k])) {
						ans = p[k];
						break;
					}
				}
				break;
			}
		} // 9961
		report_ans(ans);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/dysyn1314/p/13963433.html