https://vjudge.net/contest/342638#problem/B
题意
给你一个数列,要你找到K个不相交的区间,使得它们的和最大
思路
这里用动态规划。
d
p
[
i
]
[
j
]
表
示
我
选
出
i
个
不
相
交
的
区
间
,
并
且
选
取
了
第
j
个
数
字
的
总
和
的
最
大
值
dp[i][j]表示我选出i个不相交的区间,并且选取了第j个数字的总和的最大值
dp[i][j]表示我选出i个不相交的区间,并且选取了第j个数字的总和的最大值
那么我们可以得到状态转移方程
d
p
[
i
]
[
j
]
=
m
a
x
(
d
p
[
i
]
[
j
−
1
]
,
m
a
x
(
d
p
[
i
−
1
]
[
1
]
,
d
p
[
i
−
1
]
[
2
]
,
…
…
,
d
p
[
i
−
1
]
[
j
−
1
]
)
)
dp[i][j] = max(dp[i][j - 1] , max(dp[i - 1][1],dp[i - 1][2], …… , dp[i - 1][j - 1]))
dp[i][j]=max(dp[i][j−1],max(dp[i−1][1],dp[i−1][2],……,dp[i−1][j−1]))
因为每次更新状态都只用到上一行的状态,所以可以将空间优化为一维数组。
代码
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e3 + 5;
const ll INF = -1e18;
ll a[maxn];
ll dp[maxn];
ll MAX[maxn];
int main()
{
int n, k;
scanf("%d %d", &n, &k);
for(int i = 1; i <= n; i++)
scanf("%lld", &a[i]);
ll ans = INF;
for(int i = 1; i <= k; i++)
{
ans = INF;
for(int j = i; j <= n; j++)
{
dp[j] = max(dp[j - 1] + a[j], MAX[j - 1] + a[j]);
MAX[j - 1] = ans;
ans = max(ans, dp[j]);
}
}
printf("%lld\n", ans);
return 0;
}
#includ<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e3 + 5;
ll dp[maxn][maxn];
ll prefix[maxn];
ll a[maxn];
int main()
{
int n, k;
scanf("%d %d", &n, &k);
for(int i = 1; i <= n; i++)
{
scanf("%lld", &a[i]);
prefix[i] = prefix[i - 1] + a[i];
}
ll tmp;
for(int i = 1; i <= k; i++)
{
tmp = -1e18;
for(int j = i; j <= n; j++)
{
tmp = max(tmp, dp[i - 1][i - 1]);
if(i != j)
dp[i][j] = max(dp[i][j - 1] + a[j], tmp + a[j]);
else
dp[i][j] = prefix[i];
}
}
ll ans = -1e18;
for(int i = k; i <= n; i++)
ans = max(dp[k][i], ans);
printf("%lld\n", ans);
}
参考来源
https://blog.csdn.net/m0_38081836/article/details/84069023