• Codeforces 1305F. Kuroni and the Punishment 题解


    题目链接:F. Kuroni and the Punishment

    题目大意:给定一个正整数序列(a_1,a_2,cdots,a_n),你每一次操作可以使每一个数(+1)(-1),但必须保证操作后的数仍为正整数,问最少用多少次操作才能使它们的最大公约数不为(1)


    题解:这样的题拿到之后第一反应就是瞎搞(然而博主太菜了赛时瞎搞了16发都没对),肯定是枚举素因子然后计算答案了,我们先假设我们已经知道了素因子是什么,假设其为(p),所以有一个很明显的贪心策略,就是每一个数只会变成与它相邻的两个是(p)的倍数的正整数,所以我们就可以得到一个(O(n))的贪心策略。先把(2)(3)跑一遍(因为这两个最容易成为答案),然后就是随机了,随机抽取序列中的一个数,令其为(x),然后把(x)分解质因数,对它的每一个质因数都跑一遍,然后再这么操作(x-1)(x+1),这样的话算法错误的概率是(frac{1}{2}),然后重新随机。这样随机 20 次之后,程序错误的概率就是(2^{-20}),当然了,赛场上没有必要这么算,直接卡时间就可以了。

    下面是代码(随机函数最好用 mt19937 ,可能是博主太菜了用 rand 结果WA7):

    #include <ctime>
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    template<typename Elem>
    void read(Elem &a){
    	a=0;
    	char c=getchar();
    	while(c<'0'||c>'9'){
    		c=getchar();
    	}
    	while(c>='0'&&c<='9'){
    		a=(a<<1)+(a<<3)+(c^48);
    		c=getchar();
    	}
    }
    const int Maxn=200000;
    typedef long long ll;
    int n;
    ll a[Maxn+5];
    ll p[Maxn+5];
    int p_len;
    void div(ll x){
    	p_len=0;
    	for(ll i=2;i*i<=x;i++){
    		if(x%i==0){
    			p[++p_len]=i;
    			while(x%i==0){
    				x/=i;
    			}
    		}
    	}
    	if(x>1){
    		p[++p_len]=x;
    	}
    }
    ll work(ll p){
    	ll ans=0;
    	for(int i=1;i<=n;i++){
    		if(a[i]<p){
    			ans+=p-a[i];
    			if(ans>=n){
    				break;
    			}
    			continue;
    		}
    		ll fron=a[i]/p;
    		ll bac=(fron+1)*p;
    		fron*=p;
    		ans+=min(a[i]-fron,bac-a[i]);
    		if(ans>=n){
    			break;
    		}
    	}
    	return ans;
    }
    int main(){
    	clock_t begin,end;
    	begin=clock();
    	mt19937 rnd(time(NULL));
    	read(n);
    	for(int i=1;i<=n;i++){
    		read(a[i]);
    	}
    	ll ans=n;
    	ll num=0;
    	for(int i=1;i<=n;i++){
    		if(a[i]&1){
    			num++;
    		}
    	}
    	ans=min(ans,num);
    	num=0;
    	for(int i=1;i<=n;i++){
    		if(a[i]==1){
    			num+=2;
    		}
    		else if(a[i]%3!=0){
    			num++;
    		}
    	}
    	ans=min(ans,num);
    	while(1){
    		int x=rnd()%n+1;
    		div(a[x]);
    		for(int i=1;i<=p_len;i++){
    			ans=min(ans,work(p[i]));
    		}
    		div(a[x]-1);
    		for(int i=1;i<=p_len;i++){
    			ans=min(ans,work(p[i]));
    		}
    		div(a[x]+1);
    		for(int i=1;i<=p_len;i++){
    			ans=min(ans,work(p[i]));
    		}
    		end=clock();
    		if((end-begin)*1.0/CLOCKS_PER_SEC>2.0){
    			break;
    		}
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    
  • 相关阅读:
    Spark源码走读6——Shuffle
    Spark源码走读5——Storage
    使用Gradle构建Android应用的渠道包
    轻松搞定面试中的二叉树题目
    QT中使用微软Speech API实现语音识别
    QT 相关资源(书籍、论坛、博客等。。。)整理...
    使用Cscope阅读大型工程Linux内核的源代码教程
    搭建一个免费的,无限流量的Blog----github Pages和Jekyll入门
    RSA算法原理(二)
    RSA算法原理(一)
  • 原文地址:https://www.cnblogs.com/withhope/p/12407721.html
Copyright © 2020-2023  润新知