【题解】[Codeforces 1305F] Kuroni and the Punishment | 20210920 模拟赛 最大公约数(gcd)【随机化 抽屉原理】

题目链接

题目链接

题意

给定 (n) 个正整数,一次操作可以将其中一个加减一,求最少操作数使得所有数都是正整数且 gcd 大于 1。(nleq 2 imes 10^5,a_ileq 10^{12})

题解

注意到答案不超过 (n)(gcd=2),考虑如果 gcd 不是小质数(的倍数),那么需要加减 2 的数不超过一半。我们多次随机两个数,求其(加减一/不变)后的 gcd,并钦定 gcd 为其约数,计算代价。每次随机有不少于 (dfrac{1}{2}) 的概率正确。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll getint(){ ll x;scanf("%lld",&x);return x; }
const int N=2e5+10,K=300,T=1e4;
mt19937 rnd;
int pri[K],cnt; bool boo[K+10];

int n;
ll a[N];
map<ll,int>mp;
ll gcd(ll x,ll y){
	return x?gcd(y%x,x):y;
}
pair<ll,int>q[N];
int main(){
	freopen("gcd.in","r",stdin);
	n=getint();
	for(int i=1;i<=n;i++)a[i]=getint();
	
	for(int i=2;i<=K;i++){
		if(!boo[i])pri[cnt++]=i;
		for(int j=0;j<cnt&&i*pri[j]<=K;j++){
			boo[i*pri[j]]=0;
			if(i%pri[j]==0)break;
		}
	}
	
	ll ans=n;
	for(int i=0;i<cnt;i++){
		int p=pri[i];
		ll v=0;
		for(int j=1;j<=n;j++){
			if(a[j]<p)v+=p-a[j];
			else{
				ll t=a[j]%p;
				v+=min(t,p-t);
			}
		}
		ans=min(ans,v);
	}
	
	for(int _=0;_<10;_++){
		int x=rnd()%n+1,y=rnd()%n+1;
		for(int d:{-2,-1,0,1,2}){
		    if(min(a[x],a[y])+d<=0)continue;
			ll g=gcd(a[x]+d,a[y]+d);
			for(int j=0;j<cnt;j++)while(g%pri[j]==0)g/=pri[j];
			mp[g]++;
			
			for(int p=2;p*1ll*p<=g;p++){
				if(g%p==0){
					ll v=0;
					for(int j=1;j<=n;j++){
						if(a[j]<p)v+=p-a[j];
						else{
							ll t=a[j]%p;
							v+=min(t,p-t);
						}
					}
					ans=min(ans,v);
				}
				while(g%p==0)g/=p;
			}
			if(g!=1){
				ll p=g;
				ll v=0;
				for(int j=1;j<=n;j++){
					if(a[j]<p)v+=p-a[j];
					else{
						ll t=a[j]%p;
						v+=min(t,p-t);
					}
				}
				ans=min(ans,v);
			}
		}
	}
	cout<<ans;
}

花絮:搬题人的数据非常水,输出 (n-1) 就能过题。

知识共享许可协议
若文章内无特别说明,公开文章采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
原文地址:https://www.cnblogs.com/wallbreaker5th/p/15357994.html