题意:
给出n,a,b以及n个整数a1,a2…an, 可以对数组进行以下两种操作;
(1)花费len*a的代价删除连续的len个数,len<|S|
(2)花费b的代价将某一个a[i]加一或减一
每个数最多执行一次这样的操作;
使得这个数组所有数的GCD>1;
求最小花费;
思路:
因为删除操作不能一下子删完,所以肯定会剩下一个,那么就会是头一个或者最后一个。所以剩下的数可能有a[1]-1,a[1]+1,a[1],a[n],a[n]-1,a[n]+1。
预处理出所有数的质因子,枚举每个质因子之间默认就是整个数组的公约数.
DP:
[不变] 只能前面存在不变 或者 +/-过
[删除] 要么是从来都没有变过 开始删除, 要么是已经删除过了,继续删除
[+/- ] 前面能存在删除 或者 不变 或者 +/-过
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6+10;
const LL INF = 1e18;
LL dp[N][3]; //0: 不变; 1: +1/-1; 2: 删除
LL val[N];
LL a, b;
int n;
vector<LL>gcd;
void init(LL x){
for(LL i = 2;i * i <= x;i++){
if(x % i == 0) gcd.push_back(i);
while(x % i ==0) x /= i;
}
if(x != 1) gcd.push_back(x);
}
LL solve(LL g){
LL temp;
dp[0][0] = dp[0][1] = dp[0][2] = 0;
for(int i=1;i<=n;i++){
temp = 1e18;
if((val[i] + 1) % g == 0 || (val[i] - 1) % g == 0) temp = b;
if(val[i] % g == 0) temp = 0;
dp[i][0] = dp[i-1][0] + temp;dp[i][0] = min(dp[i][0], INF);
dp[i][2] = min(dp[i-1][1], dp[i-1][2]) + temp;dp[i][2] = min(dp[i][2], INF);
dp[i][1] = min(dp[i-1][0], dp[i-1][1]) + a;dp[i][1] = min(dp[i][1], INF);
}
return min(dp[n][0],min(dp[n][1],dp[n][2]));
}
int main(){
scanf("%d%I64d%I64d", &n, &a, &b);
for(int i=1;i<=n;i++)
scanf("%I64d", &val[i]);
gcd.clear();
init(val[1]);
init(val[1] + 1);
init(val[1] - 1);
init(val[n]);
init(val[n] + 1);
init(val[n] - 1);
sort(gcd.begin(), gcd.end());
gcd.erase(unique(gcd.begin(), gcd.end()), gcd.end());
LL ans = 2e18;
for(int i=0;i<gcd.size();i++){
ans = min(solve(gcd[i]), ans);
}
printf("%I64d\n", ans);
return 0;
}