昨天,队友们提醒我,尺取还没涉及。
搜了一道尺取法来练手,谁曾想这题真的是百般曲折,耗尽心思。
//AC
//HDU 5672 String
#include<iostream>
#include<cstring>
#include<algorithm>
#include<set>
#include<queue>
#include<stack>
using namespace std;
int vis[27];
char s[1000005];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int k;
memset(vis,0,sizeof(vis));
scanf("%s%d",s,&k);
int l=0,r=0,distinct=0;
long long res=0;
int cur=0;
int len=strlen(s);
while(l<len )
{
while(r<len && distinct<k)
{
if(vis[s[r]-'a']==0)
{
//vis[s[r]-'a']++;
distinct++;
}
vis[s[r]-'a']++;
r++;
}
if(distinct==k)
cur=len-r+1;
else cur=0;
// cout<<"cur:"<<cur<<endl;
res+=cur;
vis[s[l]-'a']--;
if(vis[s[l]-'a']==0)
{
distinct--;
}
l++;
}
printf("%lld\n",res);
}
}
开始时,就想着暴力暴力,左边端点从下标0遍历到最后,右边端点遇到distinct==k的时候,停止。
后来想到尺取法,左边端点向右移动的时候,要看舍弃的左端点在之后的序列中有没有出现过,如果只出现了一次,那么右端点就要向右走。如果出现过很多次,右端点就没有必要向右移动了。
另外,如果用string s,好像也会TLE。