文章大意:
给定一个数列,现在有两种合法操作:
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;
}