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;
} 
posted @ 2025-06-14 14:33  MinimumSpanningTree  阅读(6)  评论(0)    收藏  举报