hdu 4905 The Little Devil II 区间DP 四边形不等式优化

The Little Devil II

Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 307    Accepted Submission(s): 78


Problem Description
There is an old country and the king fell in love with a devil. The devil always asks the king to do some crazy things. Although the king used to be wise and beloved by his people. Now he is just like a boy in love and can’t refuse any request from the devil. Also, this devil is looking like a very cute Loli.

Y*wan defeat the princess's knight party, and finally he meet the devil. But, after that, y*wan feel in love with the devil and become a lolicon. As the king is already died, y*wan become the new king.

Some days passed, the devil feel bored about this boring country and leaves, but the lolicon remains in the country.

The finally hero, you comes as promised, and you figure out a hard problem to defeat y*wan:

There is n integers a_1,a_2,...,a_n on a line, each time we can take two adjacent integers a and b, and replace them by their gcd(a,b), and add gcd(a,b) to the total score. The score is initially the sum of all a_i.After n-1 steps there is only one number left and you stop. What is your maximum score in the end?

After defeat y*wan, you kill WJMZBMR, and save the country.
 

Input
The first line contains an integer T, denoting the number of the test cases.
For each test case, the first line contains an integer n.
The next line contains n integers a_1,a_2,...,a_n separated by a single space.

T<=20, n<=3000.
a_i >=0
a_i is in the range of int(C++).
 

Output
For each test case, output the result in one line.
 

Sample Input
  
  
1 4 1 2 2 4
 

Sample Output
  
  
14

  多校第四场,比赛的时候超时。。

  可以把任意两个相邻的数变成他们的gcd,并且把这个gcd加到最后的答案中去。选择合适的顺序,使最后的答案最大。

  好吧。。今天才知道有四边形不等式优化这个东西。。

  这里介绍的很详细点击打开链接

  总之如果满足四边形不等式的条件的话,区间dp的时候要记录s[i][j],第三重循环的范围是s[i][j-1]-s[i+1][j]。

#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#define INF 0x3f3f3f3f
#define MAXN 3010
#define MAXM 110
#define MOD 1000000007
#define MAXNODE 4*MAXN
#define eps 1e-9
using namespace std;
typedef long long LL;
int T,N;
int a[MAXN],g[MAXN][MAXN],s[MAXN][MAXN];
LL dp[MAXN][MAXN];
int gcd(int a,int b){
    return a%b?gcd(b,a%b):b;
}
void init(){
    for(int i=1;i<=N;i++){
        g[i][i]=a[i];
        for(int j=i+1;j<=N;j++) g[i][j]=gcd(g[i][j-1],a[j]);
    }
}
int main(){
    freopen("in.txt","r",stdin);
    scanf("%d",&T);
    while(T--){
        scanf("%d",&N);
        for(int i=1;i<=N;i++) scanf("%d",&a[i]);
        init();
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=N;i++){
            s[i][i]=i;
            dp[i][i]=a[i];
        }
        for(int l=1;l<N;l++)
            for(int i=1;i+l<=N;i++){
                int j=i+l;
                for(int k=s[i][j-1];k<=s[i+1][j];k++){
                    if(k<j&&dp[i][j]<dp[i][k]+dp[k+1][j]+g[i][j]){
                        dp[i][j]=dp[i][k]+dp[k+1][j]+g[i][j];
                        s[i][j]=k;
                    }
                }
            }
        printf("%I64d\n",dp[1][N]);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值