您的位置:首页 > 其它

[codevs4654][bzoj2442]修剪草坪(单调队列dp)

2017-09-28 19:45 337 查看

题目:

我是超链接

题解:

启明星:这题目不就是核电站?如果连起来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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: