题解
1.任何一个数,只能覆盖一次
2.把被覆盖的数字具象化,那么最终数组一定是由若干个有颜色的区间(被覆盖)和无颜色区间(没有被覆盖)组成
3.这里就是状态的巧妙之处了,已知我们要求 \(n\) 个数里最多 \(k\) 个数被覆盖的最小和,那么这 \(k\) 个数里,一定存在末尾连续 \(j\) 个数字被覆盖 ,其中 \(0 \leq j \leq k\)
设 \(dp[i][k]\) 为前 \(i\) 个数里有 \(k\) 个数字被覆盖,则 \(dp[i][k]=\min(dp[i-j-1][k-j]+\min(a[i-j]...a[i])·j)\)
code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline void read(ll &x) {
x = 0;
ll flag = 1;
char c = getchar();
while(c < '0' || c > '9'){
if(c == '-')flag = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = (x << 3) + (x << 1) + (c ^ 48);
c = getchar();
}
x *= flag;
}
inline void write(ll x)
{
if(x < 0){
putchar('-');
x = -x;
}
if(x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
ll a[300005];
ll dp[300005][15]={0};
int main()
{
ll t;
read(t);
while(t--)
{
ll n, k;
read(n);
read(k);
ll sum=0;
for(ll i=1; i<=n; i++)
{
read(a[i]);
sum += a[i];
for(ll j=0; j<=k; j++) dp[i][j] = sum;
}
for(ll i=1; i<=n; i++)
{
for(ll j=1; j<=min(i-1, k); j++)
{
ll mn = a[i];
for(ll l=0; l<=j; l++)
{
mn = min(a[i-l], mn);
dp[i][j] = min(dp[i][j], dp[i-l-1][j-l] + (l+1) * mn);
}
}
}
ll ans = 2e18;
for(ll i=0; i<=k; i++) ans = min(ans, dp[n][i]);
write(ans);
putchar('\n');
}
return 0;
}
标签:覆盖,read,Sum,while,Minimizing,数里,ll,dp
From: https://www.cnblogs.com/pure4knowledge/p/18244394