<区间DP> 【noip 2007】 矩阵取数游戏(60%)

*题目链接http://codevs.cn/problem/1166/
因为剩下的40%是高精度而且是恶心的高精度,我就先打60%吧。。。
一开始想的转移方程错了,调了一会发现不满足无后效性原则,一开始的想法是这样的:
dp[i][j]是第i次取数,取的数是第j个的最大的答案,枚举第i-1次取的数,但是这样做不能满足j之前没有被取过,因此不可以
正确的转移方程:
对于每一行:
dp[i][j]表示剩下区间[i,j]的数时的最大值。为什么要这样呢?
因为我们发现每次取走首或尾的两个数时,剩下的数一定是一个区间,我们的每个区间的答案可以由更小的区间转移过来,因此可以从小到大枚举区间长度求解
这里有一个比较巧妙的地方,就是我们每次增加一个区间长度,前一个区间的值乘以2,初始是把dp[i][i]设为ju[i],m次后,区间长度为1的答案乘以了2^(m-1),长度为2的乘以了2^(m-1),……区间长度为m的乘以了2^0,最后的答案再把dp[1][m]*2就可以了
即:
dp[i][j]=max(dp[i+1][j]*2+ju[i],dp[i][j-1]*2+ju[j]);
代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
typedef unsigned long long ll;
using namespace std;

const int maxn=100;
ll n,m,ans,ma;
ll dp[maxn][maxn],ju[maxn];

int main()
{
    cin>>n>>m;
    for(int x=1;x<=n;++x)
    {
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=m;++i) 
        {
            cin>>ju[i];
            dp[i][i]=ju[i];
        }
        for(int i=2;i<=m;++i)//枚举区间长度 
          for(int j=1;j<=m-i+1;++j)//枚举起点 
            {
                int l=j+i-1;
                dp[j][l]=max(dp[j+1][l]*2+ju[j],dp[j][l-1]*2+ju[l]);    
            }
        ans+=2*dp[1][m];  
    }
    cout<<ans;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值