CF624D - Array GCD

来源:互联网 发布:flash mac中文版 编辑:程序博客网 时间:2024/06/06 05:37

文章大意:

给定一个数列,现在有两种合法操作:

1)选择一段连续区间,把这段区间的数移除,代价为a*区间元素个数,不可移动整个数列。

2)选择某些元素,把这些元素分别加一或减一,元素之间无影响,可以不连续。代价为b*操作元素个数。

现在要求这两种操作,每种操作最多做一次,可以不做,使得剩下的数列中,所有数的最大公约数大于1。求所需的最小代价。


通过YY可以发现,既然不让移除全部区间,就是说,a1或者an至少要有一个留在原来数列,那么可以求a1,a1+1,a1-1,an,an+1,an-1,这六个数的质因数,最后的答案的约数肯定在这六个数的质因数当中。那么久简单了,先分解这六个数,求出它们的质因数(ps:注意本身是大素数的情况),然后枚举质因数,对于每个质因数,求出其最小代价,最后求最小值。

求最小值可以DP也可以尺扫,我用的是尺扫的方法,枚举移除的左右端点L和R,如果当前区间的修改代价之和大于区间移除代价,那么就移除,R++,否则,不移除,L=R+1,R=L。这个复杂度是O(n)的,有兴趣的同学可以自己证明一下这个的复杂度。注意不可以整个区间都移除,需要特判。

<代码很丑,勿喷>

#include<cstdio>#include<iostream>#include<cstring>#include<string>#include<algorithm>#include<cmath>#include<map>using namespace std;int shu[1100000];int sushu[110000];long long dai[1100000];long long ans;int n;long long a[1100000];long long aa,bb;int aaa,bbb;map<long long,int> w1,wn;int main(){for(int i=2;i<=1000000;i++){if(!shu[i]){for(int j=i*2;j<=1000000;j+=i)shu[j]=1;}}for(int i=2;i<=1000000;i++){if(!shu[i]){sushu[0]++;sushu[sushu[0]]=i;}}scanf("%d%d%d",&n,&aaa,&bbb);aa=aaa;bb=bbb;for(int i=1;i<=n;i++){int x;scanf("%d",&x);a[i]=x;}for(int i=1;i<=sushu[0];i++){if(a[1]%sushu[i]==0)w1[sushu[i]]=1;if((a[1]-1)%sushu[i]==0)w1[sushu[i]]=1;if((a[1]+1)%sushu[i]==0)w1[sushu[i]]=1;w1[a[1]]=1;w1[a[1]+1]=1;w1[a[1]-1]=1;//if(w1[sushu[i]])printf("sajfdoiajfo 1 %d\n",sushu[i]);if(a[n]%sushu[i]==0)wn[sushu[i]]=1;if((a[n]-1)%sushu[i]==0)wn[sushu[i]]=1;if((a[n]+1)%sushu[i]==0)wn[sushu[i]]=1;wn[a[n]]=1;wn[a[n]-1]=1;wn[a[n]+1]=1;//if(wn[sushu[i]])printf("sajfdoiajfo n %d\n",sushu[i]);}sushu[0]++;sushu[sushu[0]]=a[1];sushu[0]++;sushu[sushu[0]]=a[1]+1;sushu[0]++;sushu[sushu[0]]=a[n];sushu[0]++;sushu[sushu[0]]=a[n]+1;sushu[0]++;sushu[sushu[0]]=a[1]-1;sushu[0]++;sushu[sushu[0]]=a[n]-1;ans=-1;for(int i=1;i<=sushu[0];i++){if(sushu[i]==1)continue;//if(i==10)while(1);//printf("ii=%d sushu=%d\n",i,sushu[i]);if((!w1[sushu[i]])&&(!wn[sushu[i]])){}else{long long q=sushu[i];for(int j=1;j<=n;j++){if(a[j]%q==0){dai[j]=0;}else{if(((a[j]+1)%q==0)||((a[j]-1)%q==0)){dai[j]=bb;}else{dai[j]=aa*(long long)100;}}}int ji=0;long long temp=0;long long anss;for(int j=2;j<=n;j++)dai[j]+=dai[j-1];//for(int j=1;j<=n;j++){//printf("dai[%d]=",j);//cout<<dai[j]<<endl;//}anss=dai[n];for(int j=1;j<=n;j++){temp+=dai[j]-dai[j-1];ji++;if(temp>=(long long)ji*aa){anss=min(anss,dai[j-ji]+dai[n]-dai[j]+(long long)ji*aa);}else{temp=0;ji=0;}}if(ans==-1)ans=anss;ans=min(ans,anss);//printf("ans[%d]=",i);//cout<<ans<<endl;}}cout<<ans<<endl;return 0;}


0 0
原创粉丝点击