CF1305F Kuroni and the Punishment 题解
题目描述
给定 \(n\) 个数 \(a_i\) ,每次操作可以选择一个数 \(+1\) 或 \(-1\) ,求最小操作次数使得所有数为正且 \(\gcd\gt 1\) 。
数据范围
- \(2\le n\le 2\cdot 10^5,1\le a_i\le 10^{12}\) 。
时间限制 \(\texttt{2.5s}\) ,空间限制 \(\texttt{256MB}\) 。
分析
容易发现答案不超过 \(n\) ,因此至少有一半的数满足 \(a'_i\in\{a_i-1,a_i,a_i+1\}\) 。
注意到 \(\gcd\gt 1\) 等价于存在一个质因子 \(p\) 满足所有数都是 \(p\) 的倍数。
对于给定的质因子 \(p\) ,我们可以在 \(\mathcal O(n)\) 的时间内统计让所有数变成 \(p\) 的倍数的最小操作次数。
在序列中随机选择 \(k\) 个数,将其分解质因数,枚举 \(a_i-1,a_i,a_i+1\) 的质因子 \(p\) 加入候选集合。
由于 \(a_i\le 10^{12}\) ,因此 \(\omega(a_i)\le11\) ,候选集合中至多只有 \(33k\) 个质因子。
对这些质因子统计答案,时间复杂度 \(\mathcal O(k\frac{\sqrt v}{\log v}+33kn)\) 。
当且仅当最优策略不包含上述 \(k\) 个数时会出错,出错概率 \(\le\frac 1{2^k}\) ,取 \(k=30\) 即可通过。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e6+5,inf=1e18;
int n,cnt,res=inf;
int a[maxn],b[maxn],p[maxn];
set<int> s;
mt19937 rnd(random_device{}());
void init(int n)
{
for(int i=2;i<=n;i++)
{
if(!b[i]) p[++cnt]=i;
for(int j=1;j<=cnt&&i*p[j]<=n;j++)
{
b[i*p[j]]=1;
if(i%p[j]==0) break;
}
}
}
void calc(int n)
{
if(!n) return ;
for(int i=1;i<=cnt&&p[i]*p[i]<=n;i++)
{
if(n%p[i]) continue;
s.insert(p[i]);
while(n%p[i]==0) n/=p[i];
}
if(n!=1) s.insert(n);
}
void work(int p)
{
int cur=0;
for(int i=1;i<=n;i++)
{
int x=a[i]/p;
cur+=min(x?a[i]-x*p:inf,(x+1)*p-a[i]);
if(cur>=res) return ;
}
res=cur;
}
signed main()
{
scanf("%lld",&n),init(1e6);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
shuffle(a+1,a+n+1,rnd);
for(int i=1;i<=min(n,30ll);i++) calc(a[i]-1),calc(a[i]),calc(a[i]+1);
for(auto p:s) work(p);
printf("%lld\n",res);
return 0;
}
本文来自博客园,作者:peiwenjun,转载请注明原文链接:https://www.cnblogs.com/peiwenjun/p/17474641.html
浙公网安备 33010602011771号