题目:
题解:
启明星:这题目不就是核电站?如果连起来k个就会boom,只不过那里要求填尽量多的地雷,这里要权值尽量大而已。别的处理就是一样了?
f[i][j]表示前i个已经连续了j个的最大权值
如果j!=0,是从f[i-1][j-1]转移的;如果j=0,那就从f[i-1][0..k-1]中的最大值转移过来的
好像空间时间都会boom,我们怎么办呢?好像可以运用滚动数组+prority_queue优化——60pts
Emmm….这个MLE是…?哦我queueboom了,那只能手动队列了,等等,队列个P啊,为什么不手动维护最大值?这个WA好像是要用longlong?
改改改
好了第二波,Emmm….好了那些MLE的WA的现在全T了
这个1e5^2很不稳啊(这不是废话吗),运用累加思想,这一次长度到j的就是上一次j-1的加上a[i]?
逃避三天之后
阳:看来要换思路了f[i]表示前i个元素(第i个不选)的最小不选值
f[i]=min{f[j]}+a[i] 限制就是j∈[i-k+1,i-1] 这个O(nk)的效率很不ok啊
这个j明显在i之前就不会改变了【仿佛看到了昨天某题的影子
单调队列优化?就是把f[j]弄到队列中,提取就是最小值(单减的队列
最后给ans找个max
注意:这个f[i]更新的f[j]范围是到i-1,所以要把f[i]的赋值语句放到最前面;对于不到k项的元素,ta们一定会在队首,为了避免f[i] (i <= k) 被ta更新,事先给队列放一位元素0,在读满k位之前,不把0t出去
代码:
#include <cstdio>
#include <iostream>
#define LL long long
using namespace std;
struct hh{LL tim,z;}q[100005];
int a[100005];
LL f[100005];
int main()
{
LL sum=0,ans=0;
int n,k,i;
scanf("%d%d",&n,&k);
for (i=1;i<=n;i++) scanf("%d",&a[i]),sum+=(LL)a[i];
int head=1,tail=1;
for (i=1;i<=n;i++)
{
f[i]=q[head].z+a[i];
while (q[tail].z>=f[i] && head<tail) tail--;
q[++tail].z=f[i]; q[tail].tim=i;
while (q[head].tim<=i-k-1 && head<tail) head++;
}
for (i=n-k;i<=n;i++) ans=max(ans,sum-f[i]);
printf("%lld",ans);
}