CodeForces 1305F Kuroni and the Punishment
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 \times 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 \rfloor\) .
所以如果我们随机一个 \(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\n",an);
return 0;
}