Codeforces851D Arpa and a list of numbers(素數篩)
阿新 • • 發佈:2018-11-01
/*
素數篩
有n個數,可以進行兩種操作:
1,刪除一個數,花費x
2,某個數的值+1,花費y
現在想讓序列所有數的gcd>1,求最小花費。(全部刪除也合法)
列舉數列中所有的素數i,如果某個數a[j]不是i的倍數,
將其刪除花費為v1=x,增加到是i倍數花費為v2=(i-a[j]%i)*y;
(n-cnt)*x刪除所有數,(n-cnt)*y,所有數+1
*/
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn=1e6+5;
int n;
LL x,y;
int a[maxn];
LL sum[maxn];
bool is_prime[maxn];//i是否為素數
void init()//初始化
{
memset(is_prime,0,sizeof(is_prime));
for(int i=2;i<maxn;i++) is_prime[i]=1;
}
int main()
{
ios::sync_with_stdio(false);
while(cin>>n)
{
cin>>x>>y;
memset (sum,0,sizeof(sum));//某個數的個數
for(int i=0; i<n; i++)
{
cin>>a[i];
sum[a[i]]++;
}
LL ans=(LL)n*x;//刪除所有的數
LL cnt;
init();
for (int i=2;i<maxn;i++)//列舉素數,改數不進行操作
{
if(is_prime[i])
{
cnt=sum[i];//i以及i的倍數的個數
for(int j=i+i;j<maxn;j+=i)//素數篩法
{
cnt+=sum[j];
is_prime[j]=0;
}
if((n-cnt)*min(x,y)<ans)//可能有更小答案
{
LL ret=0;
for(int j=0;j<n;j++)
{
if(a[j]%i!=0)
{
LL v1=x;//刪除
LL v2=(i-a[j]%i)*y;//增加成i的倍數
ret+=min(v1,v2);
}
}
ans=min(ans,ret);//更新答案
}
}
}
cout<<ans<<endl;
}
return 0;
}