【dp】CodeForces

来源:互联网 发布:plsql导入sql文件命令 编辑:程序博客网 时间:2024/05/17 23:44

Link:http://codeforces.com/problemset/problem/623/B

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<stack>#include<queue>#include<deque>#include<map>#include<set>#include<algorithm>using namespace std;typedef long long LL;//#pragma comment(linker, "/STACK:102400000,102400000")/*CodeForces - 623B题意:给出n个数的序列,对序列可以有两种操作:1. 将一段len长的序列直接删去,消耗len*a的能量;  一个序列只能删一次,并且不能删完整个序列。2. 将一个数+1或-1,消耗b能量; 每个数只能变一次。使得序列的最大公约数大于1,消耗的能量最小值题解:因为删去的部分不会同时包含第一个数a[1]和最后一个数a[n],那么序列的最大公约数的可能性为:a[1]-1,a[1],a[1]+1,a[n]-1,a[n],a[n]+1 的质因子。据说一个数n的质因子个数为log2(n)的规模,那么其实最大公约数的可能值很小。对于已知的最大公约数,计算序列最小花费,dp如下定义:LL dp[N][5];     //0 不处理,1 处理+1-1,2 删去,3 删去用过不处理, 4 删去用过处理-1+1*/const double PI = acos(-1.0);const double eps = 1e-6;//const int INF=0x3f3f3f3f;const LL INF = 1e18;const int Mod = 1e9;const int N = 1000010;int a[N];set<int> gcd;void prime(int x){    for(int i = 2; i*i <= x; i++){        if(x%i == 0)            gcd.insert(i);        while(x%i==0)            x /= i;    }    if(x != 1)        gcd.insert(x);}int n,aa,bb;LL dp[N][5];       //0 不处理,1 处理+1-1,2 删去,3 删去用过不处理, 4 删去用过处理-1+1LL solve(int x){    for(int i = 1; i <= n; i++)        for(int j = 0; j < 5; j++)            dp[i][j] = INF;    dp[0][0] = 0;    for(int i = 1; i <= n; i++){        if(a[i]%x == 0)        {            dp[i][0] = min(dp[i-1][0],dp[i-1][1]);            dp[i][3] = min(dp[i-1][2],min(dp[i-1][3],dp[i-1][4]));        }        if((a[i]-1)%x==0 || (a[i]+1)%x==0)        {            dp[i][1] = min(dp[i-1][0],dp[i-1][1])+bb;            dp[i][4] = min(dp[i-1][2],min(dp[i-1][3],dp[i-1][4]))+bb;        }        dp[i][2] = min(dp[i-1][0],min(dp[i-1][1],dp[i-1][2]))+aa;    }    LL mi = INF;    for(int i = 0; i < 5; i++)        mi = min(mi,dp[n][i]);    //printf("%d\n",mi);    return mi;}int main(){    while(~scanf("%d%d%d",&n,&aa,&bb))    {        gcd.clear();        for(int i = 1; i <= n; i++)            scanf("%d",&a[i]);        prime(a[1]);        prime(a[1]+1);        prime(a[1]-1);        prime(a[n]);        prime(a[n]+1);        prime(a[n]-1);        LL mi = INF;        set<int>::iterator it;        for(it = gcd.begin(); it != gcd.end(); it++){            //printf("gcd = %d\n",*it);            mi = min(mi,solve(*it));        }        printf("%lld\n",mi);    }    return 0;}