Codefroces 958C2 - Encryption (medium) 区间dp

转自:https://www.cnblogs.com/widsom/p/8857777.html     略有修改

题目大意:

n个数,划分为k段,每一段的和mod p,求出每一段的并相加,求最大是多少

基本思路:

区间dp无疑

dp[i][j] 表示到第i个位置为止,分成j段的最大值

dp[i][j]=max(dp[i][j],dp[l][j-1]+(sum[i]-sum[l])%p)  0<l<i

由于n很大,p很小,所以优化一下

dp[i][j] 表示sum取模p后为i,分成j段的最大值

dp[i][j] = max(dp[i][j],dp[l][j-1] + (sum[i] - l) % p) 0<= l < p

代码如下:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<string>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>

using namespace std;

typedef long long ll;
typedef long long LL;
typedef pair<int,int> pii;
const int inf = 0x3f3f3f3f;
const int maxn = 20000+10;
const ll mod = 1e9+9;

int dp[110][60];
int a[maxn];
int main(){
    int n,k,p;
    scanf("%d%d%d",&n,&k,&p);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        a[i]+=a[i-1];
        a[i]%=p;
    }
    for(int i=0;i<p;i++){
        for(int j=0;j<=k;j++){
            dp[i][j]=-inf;
        }
    }
    dp[0][0]=0;
    for(int i=1;i<=n;i++){
        for(int j=k;j>=1;j--){
            for(int l=0;l<p;l++){
                dp[a[i]][j]=max(dp[a[i]][j],dp[l][j-1]+(a[i]-l+p)%p);
            }
        }
    }
    printf("%d\n",dp[a[n]][k]);
    return 0;
}

  

 

posted @ 2018-04-20 11:33  愿~得偿所愿,不负时光  阅读(206)  评论(0编辑  收藏  举报