首页 > 代码库 > Codeforces Round #267 (Div. 2) C. George and Job

Codeforces Round #267 (Div. 2) C. George and Job

题解:

题意:

在数组p[n]选k个长为m的连续序列。使得和最大

题解:

1.自己的解法dp[i][j]表示所选序列一定有j,选了m个片段的最大值

首先想出来的是o(n^3)解法TLE了

    for(int i=m;i<=n;i++) dp[i][1]=sum[i]-sum[i-m];
    for(int i=2;i<=k;i++)
    for(int j=i*m;j<=n;j++)
    {
        dp[j][i]=sum[j]-sum[j-m];
        ll ans=0;
        for(int p=(i-1)*m;p<=j-m;p++)  ans=max(ans,dp[p][i-1]);
        dp[j][i]+=ans;
    }

后来发现

for(int p=(i-1)*m;p<=j-m;p++)  ans=max(ans,dp[p][i-1]);

是可以优化的。是一个递增的过程,前一次用的可以在下一次继续用,降到o(n^2)了。。。

 

2.看了别人的题解

dp[i][j]表示前j个选i个序列.那么对于第j个数,可选,可不选

dp[i][j]=max(dp[i][j-1],dp[i-1][j-m]+sum[j]-sum[j-m]);

代码:

1.

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=5050;
const int mod=1e9+7;

int n,m,k;
int p[maxn];
ll sum[maxn],dp[maxn][maxn];

int main()
{
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++)
    {
         cin>>p[i];
         sum[i]=sum[i-1]+p[i];
    }
    for(int i=m;i<=n;i++) dp[i][1]=sum[i]-sum[i-m];
    for(int i=2;i<=k;i++)
    {
     int pre=(i-1)*m;
     ll ans=0;
     for(int j=i*m;j<=n;j++)
     {
         dp[j][i]=sum[j]-sum[j-m];
         for(int p=pre;p<=j-m;p++)  ans=max(ans,dp[p][i-1]);
         dp[j][i]+=ans;
         pre=j-m;
     }
    }
    ll Max=0;
    for(int i=k*m;i<=n;i++) Max=max(Max,dp[i][k]);
    cout<<Max<<endl;
    return 0;
}

2.

#include<bits/stdc++.h>
using namespace std;
#define N 5002
typedef long long ll;
ll sum[N];
ll dp[N][N];
int main()
{
  int n,m,k;
  cin>>n>>m>>k;
  for (int i=1;i<=n;i++)
  {
      int x;
      cin>>x;
      sum[i]=sum[i-1]+x;
      }
      for (int i=1;i<=k;i++)
      {
          for (int j=m*i;j<=n;j++){
          dp[i][j]=max(dp[i][j-1],dp[i-1][j-m]+sum[j]-sum[j-m]);
          }
      }
    cout<<dp[k][n]<<endl;
    return 0;
}

 

Codeforces Round #267 (Div. 2) C. George and Job