nfoi Yeah!! 弦卷心的好子串(yeah) 题解

由于是序列区间问题且无法 \(O(n^2)\),所以可以往双指针、二分什么的这类去想。其实这题两个都可以做不过双指针好写一点。
考虑寻找这题的单调性。首先右指针是固定一直从 \(1\) 到 \(n\) 一步步移动的,考虑如何发挥左指针的作用。接着,因为这题是寻找满足要求的区间个数,那就相当于每次 \(r\) 确定,有多少个 \(l\) 使得 \([l,r]\) 满足要求,再加起来即可。容易发现,这个满足要求的 \(l\) 是具有单调性的,因为如果 \([l,r]\) 满足要求,那么前面的 \(l\) 肯定也满足要求,因为相当于区间扩大了,hhw 的个数肯定要么不变,要么变多。
那么这题就变得很容易了,每轮双指针找到满足条件的最大的 \(l\),然后每轮答案加上 \(l\) 即可。对于区间变化导致的 hhw 个数变化,可以用前缀和处理。
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
const int N=1e6+100;
int n,k,l=1,r=1;
ll sum,ans,cut,sh[N],sw[N],shfw[N];
string s;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>k>>s;
s=" "+s;
for(int i=1;i<=n;i++)
{
if(s[i]=='h') sh[i]++;
if(s[i]=='w') sw[i]++;
sh[i]+=sh[i-1],sw[i]+=sw[i-1];
if(s[i]=='w') shfw[i]=sh[i];
shfw[i]+=shfw[i-1];
}
while(r<=n)
{
if(s[r]=='w') sum+=(sh[r]-sh[l-1])*(sh[r]-sh[l-1]-1)/2;
while(l<r)
{
cut=0;
if(s[l]=='h') cut=(shfw[r]-shfw[l])-(sw[r]-sw[l])*sh[l];
if(sum-cut>=k) sum-=cut,l++;
else break;
}
if(sum>=k) ans+=l;
//printf("%d %d %lld\n",l,r,sum);
r++;
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号