1. 程式人生 > >Codeforces851D Arpa and a list of numbers(素數篩)

Codeforces851D Arpa and a list of numbers(素數篩)

/*
素數篩
有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; }