Array GCD CodeForces - 624D (dp,gcd)

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

猜你喜欢

转载自www.cnblogs.com/uid001/p/10797934.html
gcd