CF1305F Kuroni and the Punishment

本文介绍了Codeforces上的CF1305F问题,这是一道涉及随机化算法的神仙题目。作者指出,通过确保GCD为2,操作数上限为n,可以得出操作次数大于等于2的数不多于n/2。因此,采用随机化策略,扰乱序列并选取前100个数,预计挂掉概率约为2^(-100)。但要注意,随机化时必须打乱序列,避免特定数据导致失败。文中反复强调随机数5224999的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接: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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值