CodeForces 1305F Kuroni and the Punishment
https://codeforces.com/contest/1305/problem/F
长度为 (n) 的正整数序列 (a_1,a_2,cdots,a_n) ,一次操作可以选择一个 (a_i) 并对其+1或-1且满足操作后 (a_i) 仍为正整数.
问最少需要多少次操作才可以使序列的gcd不为1
(2 le n le 2 imes 10^5,1 le a_i le 10^{12})
Tutorial
如果我们选择一个素数 (d) 表示最后的gcd为 (d) 的倍数,那么很容易可以在 (O(n)) 的时间内计算出这样的答案.现在我们需要检验可能为答案的 (d) .
考虑当 (d=2) 时,答案最多为 (n) ,所以对于最优的 (d) ,操作次数 (>1) 的 (a_i) 数量不超过 (lfloor dfrac n2 floor) .
所以如果我们随机一个 (a_i) ,用 (a_i-1,a_i,a_i+1) 的所有质因子作为 (d) 进行检验,那么有 (dfrac 12) 的几率得到正确答案.
则我们随机 (T=20) 个 (a_i) 进行检验,最后WA的概率为 (2^{-20}) .足以得到AC
设 (A=max{a_i}) ,则时间复杂度为 (O(T(sqrt A + n log A))) .
Code
#include <algorithm>
#include <cstdio>
#include <iostream>
#include <map>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define fi first
#define se second
using namespace std;
template<class T> inline bool Cmin(T &x,T y) {return x>y?x=y,1:0;}
typedef unsigned long long ull;
typedef long long ll;
const ll inf=1e18;
const int maxn=2e5+50;
ll an;
ll a[maxn];
int n;
map<ll,int> prime;
inline ull Rand()
{
static ull seed=0;
seed^=rand();
seed^=seed<<13;
seed^=seed>>17;
seed^=seed<<5;
return seed;
}
void work(ll x)
{
if(x==0) return;
for(int i=2;i<=x/i;++i) if(x%i==0)
{
prime[i]=1;
while(x%i==0) x/=i;
}
if(x>1) prime[x]=1;
}
ll sol(ll x)
{
ll an=0;
for(int i=1;i<=n;++i)
{
if(a[i]<=x) an+=x-a[i];
else an+=min(a[i]%x,x-a[i]%x);
}
return an;
}
int main()
{
srand((unsigned long long)(new char));
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%I64d",&a[i]);
}
ll an=inf;
int T=20; while(T--)
{
int x=Rand()%n+1;
prime.clear();
work(a[x]),work(a[x]-1),work(a[x]+1);
for(map<ll,int>::iterator it=prime.begin();it!=prime.end();++it)
{
Cmin(an,sol(it->fi));
}
}
printf("%I64d
",an);
return 0;
}