【尺取】HDU String
http://acm.hdu.edu.cn/showproblem.php?pid=5672
【题意】
给定一个小写英语字母组成的字符串,求这个字符串一共包含多少个至少有m个不同字母的连续子序列
【思路】
尺取。
我们发现,如果i~j是恰好含有k个字母的区间,那么对于k(j<k<=n),i~k是含有至少k个不同字母的子串,那么对于每一个左边界,我们都可以找到一个最小的右边界,使得这个区间恰好含有k个字母,然后统计以这个左边界符合条件的子串个数,找到右边界,用尺取法即可。
【Accepted】
1 #include <iostream> 2 #include <stdio.h> 3 #include <cmath> 4 #include <vector> 5 #include <algorithm> 6 #include <set> 7 #include <map> 8 #include <queue> 9 #include <deque> 10 #include <stack> 11 #include <string> 12 #include <bitset> 13 #include <ctime> 14 #include<algorithm> 15 #include<cstring> 16 using namespace std; 17 typedef long long ll; 18 const int maxn=1e6+2; 19 char s[maxn]; 20 int n,m; 21 int vis[27]; 22 ll solve() 23 { 24 int l=0,r=0; 25 ll res=0; 26 memset(vis,0,sizeof(vis)); 27 int num=0; 28 while(l<n && r<n) 29 { 30 while(r<n && num<m) 31 { 32 if(!vis[s[r]-'a']) 33 { 34 num++; 35 } 36 vis[s[r]-'a']++; 37 r++; 38 } 39 if(num==m) 40 { 41 res+=(n-r+1); 42 while(l<=r && vis[s[l]-'a']>1) 43 { 44 res+=n-r+1; 45 vis[s[l]-'a']--; 46 l++; 47 } 48 vis[s[l]-'a']=0; 49 num--; 50 l++; 51 } 52 53 } 54 return res; 55 } 56 int main() 57 { 58 int T; 59 scanf("%d",&T); 60 while(T--) 61 { 62 scanf("%s%d",s,&m); 63 n=strlen(s); 64 ll ans=solve(); 65 cout<<ans<<endl; 66 } 67 return 0; 68 }