codeforces 958C2 区间DP

codeforces 958C2


题意:

n k p 给定一串长度为n的数字,将其分割为k段区间。各段区间数字相加,对p取模。
k 问k段区间最大和。


题解:

d p [ i ] [ j ] i j s u m [ i ] [ 1 , i ] dp[i][j]表示长度为i的子串分割为j段的最优解,用sum[i]维护区间[1,i]的前缀和。

  • d p [ i ] [ j ] = m a x ( d p [ i ] ] [ j ] , d p [ i ] [ j 1 ] + ( s u m [ r ] s u m [ l ] + p ) % p ) dp[i][j] = max(dp[i]][j], dp[i][j-1]+(sum[r]-sum[l]+p)\%p)
  • a n s = d p [ n ] [ k ] ans=dp[n][k]

时间复杂度

  • O ( n 2 k ) O(n^2k)

区间DP优化


n 20000 f [ i ] < p 100 1 l 0 p 由于n≤20000,显然超时。而f[i]<p≤100,故将枚举1—l改为枚举0—p。
d p [ f [ i ] ] [ j ] f [ i ] j dp[f[i]][j]表示值为f[i]的子串分割为j段的最优解。

  • d p [ f [ i ] ] [ j ] = m a x ( d p [ f [ i ] ] [ j ] , d p [ m o d ] [ j 1 ] + ( s u m [ i ] m o d + p ) % p ) dp[f[i]][j] = max(dp[f[i]][j], dp[mod][j-1]+(sum[i]-mod+p)\%p)
  • a n s = d p [ s u m [ n ] ] [ k ] ans=dp[sum[n]][k]

时间复杂度

  • O ( p 2 k ) O(p^2k)

#include <bits\stdc++.h>
using namespace std;
const int N = 20001;
long long sum[N];
long long dp[N][51];

int main() {
    int n, k, p, x;
    cin >> n >> k >> p;
    for(int i = 1 ; i <= n ; i++){
        cin >> x;
        sum[i] = (sum[i-1]+x)%p;
    }
    for(int i = 0 ; i <= p ; i++){
        for(int j = 0 ; j <= k ; j++){
            dp[i][j] = -1 << 30;
        }
    }
    dp[0][0] = 0;
    for(int i = 1 ; i <= n ; i++){
       for(int j = 1 ; j <= k ; j++){
           for(int mod = 0 ; mod <= p ; mod++){
               dp[sum[i]][j] = max(dp[sum[i]][j], dp[mod][j-1]+(sum[i]-mod+p)%p);
           }
       }
    }
    cout << dp[sum[n]][k] << endl;
    return 0; 
}

猜你喜欢

转载自blog.csdn.net/CSDN_PatrickStar/article/details/89739926