1. 程式人生 > >【尺取】HDU String

【尺取】HDU String

字符串 不同 ring ref target () int 技術 找到

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

【尺取】HDU String