hdu 5900QSC and Master(区间dp 沈阳网络赛)

来源:互联网 发布:京东和淘宝哪个好 编辑:程序博客网 时间:2024/06/05 03:47

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5900
题意:

给出n对数keyi,vali表示当前这对数的键值和权值,可以操作将连续的两个数合并,如果满足gcd(a[i],a[i+1])>1,得到的价值是两个数的权值和,每次合并两个数之后,这两个数就会消失,然后旁边的数会接上

分析:

1:处理出任意区间内的所有数是否可以合并,对于当前的[l,r]区间,如果区间[l+1,r-1]可以合并,且gcd(a[l]+a[r])>1的话,则整个区间[l,r]可以合并。
2:区间dp,对于当前的l,r区间,如果要拿走l,那么枚举和l可以匹配的点i,并且【l,i】整个区间可以合并,那么就可以拿走l,也可以不选择拿走l。

代码:

#include<bits/stdc++.h>using namespace std;const int INF=0x3f3f3f3f;const int N=333;typedef long long ll;ll dp[N][N];int a[N];ll b[N],sum[N];bool ok[N][N],match[N][N];int gcd(int a,int b) {    return b==0?a:gcd(b,a%b);}bool judge(int l,int r) {    if(l>r)return 1;    return ok[l][r];}void init(int n) {    memset(match,0,sizeof(match));    memset(ok,0,sizeof(ok));    for(int i=1; i<=n; i++) {        for(int j=i+1; j<=n; j++)            match[i][j]=gcd(a[i],a[j])>1?1:0;    }    for(int l=1; l<n; l++) {        for(int i=1; i+l<=n; i++) {            int j=i+l;            ok[i][j]=0;            for(int k=i+1; k<=j; k++)                if(match[i][k]&&judge(i+1,k-1)&&judge(k+1,j))ok[i][j]=1;        }    }}ll dfs(int l,int r) {    if(l>=r)return 0;    if(dp[l][r]>=0LL)return dp[l][r];    ll& ans=dp[l][r];    ans=0LL;    for(int i=l+1; i<=r; i++) {        if(ok[l][i])ans=max(ans,dfs(i+1,r)+sum[i]-sum[l-1]);    }    ans=max(ans,dfs(l+1,r));    return ans;}int main() {  //  freopen("f.txt","r",stdin);    int T,n;    scanf("%d",&T);    while(T--) {        scanf("%d",&n);        for(int i=1; i<=n; i++)scanf("%d",&a[i]);        for(int i=1; i<=n; i++) {            scanf("%lld",&b[i]);            sum[i]=sum[i-1]+b[i];        }        init(n);        memset(dp,-1,sizeof(dp));        printf("%lld\n",dfs(1,n));    }    return 0;}
0 0
原创粉丝点击