Gym - 101234J Zero Game (单调队列优化dp)

Posted asdfsag

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gym - 101234J Zero Game (单调队列优化dp)相关的知识,希望对你有一定的参考价值。

题意:有一个长度为n的01序列,你可以移动k次,每次将一个数移到任意一个位置,求经过操作后区间连续最大的连续0的个数。

“移动”操作看似情况很复杂,不好讨论,但其实无非就两种情况:

一、移动的是1:显然最优的策略是将1移动到最边上(相当于“移走”),目的是将两段连续的0合并。

二、移动的是0:最优策略是将小堆中的0移动到大堆里,目的是增加大堆中0的个数。

这样一来,情况就简单多了,问题转化成了求“将一段连续区间中的0合并,然后剩下的操作次数用于把其他地方的0引进来”的最优解,即求$min(max\left\\sum\limits_i\leqslant j,cnt0(i,j)\leqslant k(cnt0(i,j)+(k-cnt1(i,j)))\right\,cnt0(1,n))$,前缀和+单调队列搞一搞就行了。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N=1e6+10;
 5 char s[N];
 6 int n,m,k,a[N],b[N],hd,tl;
 7 struct P int x,y; q[N];
 8 int main() 
 9     scanf("%s",s+1),n=strlen(s+1);
10     for(int i=1; i<=n; ++i)a[i]=a[i-1]+(s[i]==0),b[i]=b[i-1]+(s[i]==1);
11     scanf("%d",&m);
12     while(m--) 
13         int ans=0;
14         scanf("%d",&k);
15         hd=tl=0;
16         for(int j=0,i=0; j<=n; ++j) 
17             for(; i<=j&&b[j]-b[i-1]>k; ++i);
18             for(; hd<tl&&q[hd].x<i-1; ++hd);
19             P np= j,a[j]-b[j];
20             for(; hd<tl&&q[tl-1].y>=np.y; --tl);
21             q[tl++]=np;
22             ans=max(ans,(a[j]-b[j])+(k-q[hd].y));
23         
24         ans=min(ans,a[n]);
25         printf("%d\n",ans);
26     
27     return 0;
28 

 

以上是关于Gym - 101234J Zero Game (单调队列优化dp)的主要内容,如果未能解决你的问题,请参考以下文章

CF Gym Dice Game BFS 暴搜

Gym - 101438F Tree Game

GCD Guessing Game Gym - 100085G 猜数字 gcd

Reverse Game(Gym - 103102B )

Game of Cards Gym - 101128G (SG函数)

[Gym-101981J] Prime Game (组合计数)