题解
\(200\)的数据范围容易想到dp。
状态:\(dp[i][j]\):满足条件下前\(i\)个数中选出\(j\)个(必须选\(i\))的最大价值和 。因为我们需要知道\(i\)和上一个选出的相片是否可以覆盖其间的区间,因此必须选\(i\)。
初始值:\(dp[i][0]=0,dp[i][j]=-inf\quad (0\le i\le n,1\le j\le x)\)
转移方程:
\[dp[i][j]=max_{p=max(i-k,0)}^{i-1} dp[p][j-1]+a[i]\quad (j>1)\\dp[i][1]=a[i]\quad (i\le k) \]第一行的方程枚举上一个选出的相片下标\(p\),为使\([p,i]\)区间可被覆盖,\(p\ge max(i-k,0)\)。当只选\(i\)一张相片时则须保证\([1,i]\)可被覆盖,需单独处理。
答案:\(ans=max_{i=n-k+1}^ndp[i][x]\)。
因为初始值为\(-inf\),对答案无影响,\(i\)下界为\(1\)亦可。如果\(ans<0\)则无合法状态,输出-1。
AC代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=210;
int dp[N][N],a[N];//dp[i][j]:满足条件下前i个数中选出j个(必须选i)的最大和
signed main()
{
int n,k,x,ans=0;
scanf("%lld%lld%lld",&n,&k,&x);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
memset(dp,-0x3f,sizeof(dp));
for(int i=0;i<=n;i++) dp[i][0]=0;
for(int i=1;i<=n;i++)
{
if(i<=k) dp[i][1]=a[i];
for(int j=2;j<=min(i,x);j++)
for(int p=max(0ll,i-k);p<i;p++) dp[i][j]=max(dp[i][j],dp[p][j-1]+a[i]);
}
for(int i=n-k+1;i<=n;i++) ans=max(ans,dp[i][x]);
if(ans<=0) printf("-1");
else printf("%lld",ans);
return 0;
}