codeforces 127 201C 双向DP

有n个点排成一行,每两个点有一个权值。现在你可以从任何一个点出发,去遍历其他点,每经过两个相邻点之间的边,边的权值就会减1,求最多能走的步数
用两个dp数组记录往左走和往右走的最大步数
dp1[i][0]表示从i往左走最多能走的步数
dp1[i][1]表示往左走并回到i最多能走的步数
 
dp2同理
然后遍历一遍就可得答案
View Code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 100010;
long long num[maxn];
long long dp1[maxn][2],dp2[maxn][2];
inline long long  max(long long  a,long long b){
    return a>b?a:b;
}
inline void  Max(long long &ans,long long cmp){
    if(cmp>ans) ans=cmp;
}
int main()
{
    int n,i,j,k;
    scanf("%d",&n);
    for(i=2;i<=n;i++) scanf("%lld",&num[i]);
    dp1[1][0]=0;dp1[1][1]=0;
    for(i=2;i<=n;i++)
    {
        if(num[i]>1) dp1[i][1]=dp1[i-1][1]+num[i]/2*2;
        else dp1[i][1]=0;
        if(num[i]&1) dp1[i][0]=dp1[i-1][0]+num[i];
        else dp1[i][0]=max(dp1[i][1],dp1[i-1][0]+num[i]-1);
    }
    dp2[n][0]=0;dp2[n][1]=0;
    for(i=n-1;i>=1;i--)
    {
        if(num[i+1]>1) dp2[i][1]=dp2[i+1][1]+num[i+1]/2*2;
        else dp2[i][1]=0;
        if(num[i+1]&1) dp2[i][0]=dp2[i+1][0]+num[i+1];
        else dp2[i][0]=max(dp2[i][1],dp2[i+1][0]+num[i+1]-1);
    }
    long long ans=0;
    for(i=1;i<=n;i++)
    {
        Max(ans,dp1[i][1]+dp2[i][0]);
        Max(ans,dp2[i][1]+dp1[i][0]);
    }
    printf("%I64d\n",ans);//好悲剧,竟然用了%lld,害的我找了半天
    return 0;
}

 

同类型的题poj2479

posted @ 2012-07-01 02:25  Because Of You  Views(600)  Comments(0Edit  收藏  举报