1.(467C)http://codeforces.com/problemset/problem/467/C
题意:有一个长为n的序列,选取k个长度为m的子序列(子序列中不能有位置重复),求所取的k个序列求和的最大值是多少
分析:设dp[i][j]在[j,n]范围内取了i个子序列求和所得的最大值,用sum[i]表示[1,i]的求和。转移方程为dp[i][j]=max(dp[i-1][j+m]+sum[j+m-1]-sum[j-1],dp[i][j+1]),表示要不要选择[j,j+m-1]这段为其中一个子序列
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 typedef long long ll; 6 const ll maxn=5050; 7 ll dp[maxn][maxn],a[maxn],sum[maxn]; 8 9 int main() 10 { 11 ll n,m,k,i,j,x,y,z,ans; 12 while ( scanf("%lld%lld%lld",&n,&m,&k)!=EOF ) { 13 for ( i=1;i<=n;i++ ) scanf("%lld",&a[i]); 14 sum[0]=0; 15 for ( i=1;i<=n;i++ ) sum[i]=sum[i-1]+a[i]; 16 memset(dp,0,sizeof(dp)); 17 ans=0; 18 for ( i=1;i<=k;i++ ) { 19 dp[i][n-i*m+1]=sum[n]-sum[n-i*m]; 20 for ( j=n-i*m;j>0;j-- ) { 21 dp[i][j]=max(dp[i-1][j+m]+sum[j+m-1]-sum[j-1],dp[i][j+1]); 22 } 23 } 24 for ( i=1;i<=n-k*m+1;i++ ) ans=max(ans,dp[k][i]); 25 printf("%lld\n",ans); 26 } 27 return 0; 28 }