大意: 给定序列, 给定常数a,b, 两种操作, (1)任选一个长为$t$的子区间删除(不能全部删除), 花费t*a. (2)任选$t$个元素+1/-1, 花费t*b. 求使整个序列gcd>1的最少花费.
题目有个限制是不能全部删除, 所以最后一定剩余a[1]或a[n], 暴力枚举a[1]与a[n]的所有素因子即可.
这场div. 2题目感觉都挺简单的, 但实现起来各种出错………..各种细节还是没考虑好……
#include <iostream>
#include <vector>
#include <cmath>
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define pb push_back
using namespace std;
typedef long long ll;const ll INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6+10;
int n, x, y;
int a[N], b[N];
ll ans, dp[3][N];ll solve(int g, int *a, int n) {
memset(dp,0x3f,sizeof dp);
dp[0][0]=dp[1][0]=dp[2][0]=0;
REP(i,1,n) {
dp[0][i] = dp[0][i-1];
dp[1][i] = min(dp[0][i-1]+x,dp[1][i-1]+x);
dp[2][i] = min({dp[0][i-1],dp[1][i-1],dp[2][i-1]});
if (a[i]%g) {
if ((a[i]-1)%g==0||(a[i]+1)%g==0) dp[0][i]+=y,dp[2][i]+=y;
else dp[0][i]=dp[2][i]=INF;
}
}
return min(dp[1][n],dp[2][n]);
}vector<int> fac(int num) {
int mx = sqrt(num+0.5);
vector<int> v;
REP(i,2,mx) if (num%i==0) {
v.pb(i);
while (num%i==0) num/=i;
}
if (num>1) v.pb(num);
return v;
}void solve(int num, int *a, int n, int tp) {
vector<int> g = fac(num);
for (auto &&t:g) ans = min(ans, solve(t,a,n)+tp*y);
}int main() {
scanf("%d%d%d", &n, &x, &y);
REP(i,1,n) scanf("%d", a+i);
ans = INF;
solve(a[1],a+1,n-1,0);
solve(a[1]-1,a+1,n-1,1);
solve(a[1]+1,a+1,n-1,1);
solve(a[n],a,n-1,0);
solve(a[n]-1,a,n-1,1);
solve(a[n]+1,a,n-1,1);
printf("%lld\n", ans);
}