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