大意: 给定序列, 给定常数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); }