CF1305F Kuroni and the Punishment

it2025-07-25  10

题目链接:https://codeforces.com/contest/1305/problem/F 这是一道很神仙的题 算法就是我们一般不常用的随机化

我们发现,这个玩意的操作上线是 n n n,只要以 2 2 2作为最终的 G C D GCD GCD即可

此时,也就是说操作次数 > = 2 >=2 >=2的数的个数 < = n / 2 <=n/2 <=n/2,于是我们可以想到随机化,我们先打乱整个序列,然后从中选出前 100 100 100个数,认为它们只操作不超过一次。

由于随机选出一个数操作次数大于等于 2 2 2的概率不超过 1 / 2 1/2 1/2,也就是说挂掉的概率大概为 1 2 100 \frac{1}{2^{100}} 21001

最后一点要强调的是,我们随机的时候要打乱序列,否则很可能会像我一样被出题人"善意"的数据卡掉

随机数 5224999 5224999 5224999万岁!!! 随机数 5224999 5224999 5224999万岁!!! 随机数 5224999 5224999 5224999万岁!!!

C o d e Code Code

#include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <ctime> #include <algorithm> using namespace std; #define int long long #define max(a, b) a > b? a : b #define min(a, b) a < b? a : b const int MAXN = 2e5, MAXP = 1e6; int a[MAXN + 10], num[MAXN + 10], top = 0; int prime[MAXP + 10], vis[MAXP + 10], tot = 0; inline int read(); void euler(int n){ for (register int i = 2; i <= n; ++i){ if (!vis[i]){prime[++tot] = i, vis[i] = i;} for (register int j = 1; j <= tot && prime[j] * i <= n; ++j){ if (prime[j] > vis[i]) break; vis[i * prime[j]] = prime[j]; } } } void get_prime(int n){ for (register int i = 1; i <= tot && prime[i] * prime[i] <= n; ++i){ if (n % prime[i] == 0){ if (!vis[i]) num[++top] = prime[i], vis[i] = 1; while (n % prime[i] == 0) n /= prime[i]; } } if (n > 1) num[++top] = n; } int get_ans(int x, int n){ int ans = 0; for (register int i = 1; i <= n; ++i){ int sum = min(a[i] % x, x - a[i] % x); if (a[i] < x) sum = x - a[i]; ans += sum; } cerr << x << " " << ans << endl; return ans; } signed main(){ freopen ("std.in", "r", stdin); freopen ("std.out", "w", stdout); srand(time(0) * 5224999); int n = read(), ans = 2e5; euler(1e6); memset(vis, 0, sizeof(vis)); for (register int i = 1; i <= n; ++i) a[i] = read(); random_shuffle(a + 1, a + n + 1); int mx = min(n, 100); for (register int i = 1; i <= mx; ++i){ get_prime(a[i]), get_prime(a[i] - 1), get_prime(a[i] + 1); } for (register int i = 1; i <= top; ++i) ans = min(ans, get_ans(num[i], n)); printf("%lld\n", ans); return 0; } inline int read(){ int x = 0; char c = getchar(); while (!isdigit(c))c = getchar(); while (isdigit(c))x = (x << 1) + (x << 3) + (c & 15), c = getchar(); return x; }
最新回复(0)