题意:一个数列,2个操作,1:删除某个数 代价为x, 2:使得其中一个数+1,代价为 y,问怎样使得这个数列为好数列,好数列定义为这个数列gcd不为1
思路:枚举gcd,比如当gcd == x 时 ,我们对于 k*x 到 (k+1)*x这个区间内 ,要么让里面的数字靠近 (k+1)*x,要么删去, 而且我们假设我们对于某个数字改变p次的时候 代价比删除他要小 ,即 pos *y <=x;
我们就可以得到在(k+1)*x - pos 到(k+1)*x里面的数字应该选择2操作,前面的选择1操作,前缀和预处理 ,当然我们不用枚举2到1e6,只需要枚举 素数即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 5 const int M=2e6+100; 6 7 ll b[M],c[M]; 8 int n; 9 ll x,y; 10 11 int main(){ 12 scanf("%d%lld%lld",&n,&x,&y); 13 int z; 14 for(int i=1;i<=n;i++){ 15 scanf("%d",&z); 16 b[z]++; 17 c[z]+=z; 18 } 19 for(int i=1;i<M;i++){ 20 b[i]+=b[i-1]; 21 c[i]+=c[i-1]; 22 } 23 int pos=x/y; 24 ll ans=n*x; 25 for(int i=2;i<=1000000;i++){ 26 ll t=0; 27 for(int j=i;j<=1000000+i&&t<ans;j+=i){ 28 int k=max(j-i,j-pos-1); 29 ll xx=(b[j]-b[k])*(ll)j-(c[j]-c[k]); 30 t+=xx*y; 31 t+=(b[k]-b[j-i])*x; 32 } 33 ans=min(ans,t); 34 } 35 cout<<ans<<endl; 36 }
枚举素数的,
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=1e6+100; 5 const int M=2e6+100; 6 7 ll b[M],c[M]; 8 int n; 9 ll x,y; 10 int a[N]; 11 int l,vis[N]; 12 13 void init(){ 14 for(int i=2;i<=N;i++){ 15 if(vis[i]==0) a[++l] =i; 16 else continue; 17 for(int j=i;j<=N;j+=i) 18 vis[j]=1; 19 } 20 } 21 int main(){ 22 init(); 23 scanf("%d%lld%lld",&n,&x,&y); 24 int z; 25 for(int i=1;i<=n;i++){ 26 scanf("%d",&z); 27 b[z]++; 28 c[z]+=z; 29 } 30 for(int i=1;i<M;i++){ 31 b[i]+=b[i-1]; 32 c[i]+=c[i-1]; 33 } 34 int pos=x/y; 35 ll ans=n*x; 36 int r=1; 37 for(int kk=1;kk<=l;kk++){ 38 ll t=0; 39 int i=a[kk]; 40 for(int j=i;j<=1000000+i&&t<ans;j+=i){ 41 int k=max(j-i,j-pos-1); 42 ll xx=(b[j]-b[k])*(ll)j-(c[j]-c[k]); 43 t+=xx*y; 44 t+=(b[k]-b[j-i])*x; 45 } 46 ans=min(ans,t); 47 } 48 cout<<ans<<endl; 49 }