【尺取】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 }
View Code

 

posted @ 2017-06-08 19:39  shulin15  阅读(271)  评论(0编辑  收藏  举报