预计是以后感觉比较有价值并且不好明确分为某一类的题都放在里面
[ABC124D] Handstand
每次操作可以对一个子串反转,仔细想一下,不难想到每次应该都是对一个全为0的子串进行反转。因为假如我们将一个串进行操作使其变成全部为1,只对0操作的总操作数是一定是最低的。因为如果对1操作还需要额外多进行操作将1变回来,即使在0比1多的情况下也是如此(0串的数量最多只会比1串多1,在这种情况下操作0的数量和先操作全部再操作1的数量相同)。
然后我们明确我们反转每次只会对一个整体0串处理,这时就可以把所有串分割开并表示为数字的形式来计算他们的贡献。
比如1100这个串里,1的数量是2,0的数量也是2,他们对长度的贡献都相同,那么如何区分呢?我们将0串标记为负数即可。然后将他们各自的贡献存进一个数组里。比如110011110,存到数组里就是2 -2 4 -1.
接下来怎么做?我们知道我们最多有k次对0块进行操作的机会。那么我们就可以维护一个滑动窗口,时刻记录窗口中负数的数量令其不大于k。
然后进队时维护队列的总贡献即可。
坑点:一般来说负数是可以入队的,但当k=0时负数连队都不能入也不能计算贡献,因此需要特判,卡了我挺久
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int n,k;
int a[maxn],dp[maxn];
char c[maxn];
queue <int> q;
int main()
{
cin>>n>>k;
scanf("%s",c+1);
c[0]='!';
int s=1,cnt=0;
for(int i=1;i<=n;i++)
{
if(c[i]!=c[i+1])
{
if(c[i]=='0') a[++cnt]=-1*s;
else a[++cnt]=s;
s=1;
}
else s++;
}
int sum=0,ans=0,nowsum=0;
for(int i=1;i<=cnt;i++)
{
if(a[i]<0)
{
if(sum<k) {sum++;}
else
{
while(!q.empty()&&q.front()>0) nowsum-=q.front(),q.pop();
if(!q.empty())
{
nowsum+=q.front();
q.pop();
}
}
}
if(k!=0||a[i]>0) {q.push(a[i]);nowsum+=abs(a[i]);}
ans=max(ans,nowsum);
}
cout<<ans;
return 0;
}
标签:nowsum,int,负数,maxn,操作,杂题,数量
From: https://www.cnblogs.com/miku-dayo/p/18129846