codeforces 958C2
题意:
给
定
一
串
长
度
为
n
的
数
字
,
将
其
分
割
为
k
段
区
间
。
各
段
区
间
数
字
相
加
,
对
p
取
模
。
给定一串长度为n的数字,将其分割为k段区间。各段区间数字相加,对p取模。
给定一串长度为n的数字,将其分割为k段区间。各段区间数字相加,对p取模。
问
k
段
区
间
最
大
和
。
问k段区间最大和。
问k段区间最大和。
题解:
d p [ i ] [ j ] 表 示 长 度 为 i 的 子 串 分 割 为 j 段 的 最 优 解 , 用 s u m [ i ] 维 护 区 间 [ 1 , i ] 的 前 缀 和 。 dp[i][j]表示长度为i的子串分割为j段的最优解,用sum[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) 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] ans=dp[n][k]
时间复杂度
- O ( n 2 k ) O(n^2k) O(n2k)
区间DP优化
由
于
n
≤
20000
,
显
然
超
时
。
而
f
[
i
]
<
p
≤
100
,
故
将
枚
举
1
—
l
改
为
枚
举
0
—
p
。
由于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段的最优解。
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) 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] ans=dp[sum[n]][k]
时间复杂度
- O ( p 2 k ) O(p^2k) O(p2k)
#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;
}