• # codeforce 1350 F. Kuroni and the Punishment (思维+随机化大法+shuffle洗牌)


    题意

    给出n<=2e5个数,对每一个数x<=1e12进行一次操作可以使其+1,-1,求最小的操作次数,使得最后整个序列的gcd不为1,并且所有数都是正数

    思路

    整个序列的gcd不为1,也就是变换后序列每个数都有一个公共因子p,一个数x经过变换之后含因子p需要操作的次数为:

    1. if(x<p) cnt=p-x%p
    2. if(x>=p) cnt=min(p-x%p,x%p)

    如果当gcd为2时,每个数最多只需要操作一次,那么操作次数上限就是n。
    上限是n可以得出如果有某些数操作次数大于1,那么这些数的个数一定小于(lfloor frac{n}{2} floor),如果大于,总次数就会大于n。

    随机在序列中选一个数,它只需要操作<=1次的概率为(frac{1}{2}),随机选30个数,里面没有一个数是只操作<=1次的概率是(1-frac{1}{2}^{30}),概率值极小。所以可以随机取30个数,将每个数x,x-1,x+1的质因子求出来,最终序列的公共因子p就存在这些质因子中。

    随机取序列中的30个数,可以使用洗牌函数shuffle,以当前时间作为随机数种子。
    细节参考shuffle详解

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=2e5+5;
    typedef long long LL;
    LL a[maxn];
    set<LL> s;
    int n;
    
    inline void addPrime(LL x){
        int sqr=sqrt(x);
        for(int i=2;i<=sqr;++i)
            if(x%i==0){
                s.insert(i);
                while (x%i==0)x/=i;
            }
        if(x>1)s.insert(x);
    }
    inline LL sol(LL p){
        LL res=0;
        for(int i=0;i<n;++i){
            LL y=a[i];
            if(a[i]<p)res+=(p-y%p);
            else res+=min(p-y%p,y%p);
        }
        return res;
    }
    int main(){
        cin>>n;
        for(int i=0;i<n;i++)cin>>a[i];
    
        unsigned seed=chrono::system_clock::now().time_since_epoch().count();
        shuffle(a,a+n,default_random_engine(seed));
    
        for(int i=0;i<n&&i<30;++i){
            addPrime(a[i]);
            addPrime(a[i]+1);
            if(a[i]>1)addPrime(a[i]-1);
        }
    
        LL mx=maxn;
        for(LL x : s){
            mx=min(mx,sol(x));
        }
        cout<<mx<<endl;
        return 0;
    }
    
  • 相关阅读:
    linux下创建一个指定大小的文件
    批量替换多个文件中的字符串
    redhat 搭建yum 源
    python ConfigParser 模块
    python yaml 模块
    python xml文件处理
    py2exe 和pyinstaller打包
    wxpython 学习之 --threading
    wxpython 学习之 --文本框与Boxsizer布局管理器
    wxpython 学习之 --窗口分割
  • 原文地址:https://www.cnblogs.com/sstealer/p/13297709.html
Copyright © 2020-2023  润新知