hdu 5056 Boring count (类似单调队列的做法。。)
给一个由小写字母构成的字符串S,问有多少个子串满足:在这个子串中每个字母的个数都不超过K。
数据范围:
1<=T<= 100
1 <= the length of S <= 100000
1 <= K <= 100000
思路:
考虑以S[i]结尾的子串,若以S[j] (j<i)作为头不能构成一个符合条件的子串,则S[1]...S[j]都不能作为子串的头。
若S[j+1]可以作为子串的头,则以S[i]结尾的符合条件的子串个数是i-j。
做法:单调队列的思想,不多解释,直接看代码。
代码:
#include <cstdio> #include <iostream> #include <string.h> #include <cstdlib> #include <algorithm> #include <queue> #include <vector> #include <cmath> #include <map> #include <stack> using namespace std; int const uu[4] = {1,-1,0,0}; int const vv[4] = {0,0,1,-1}; typedef long long ll; int const maxn = 50005; int const inf = 0x3f3f3f3f; ll const INF = 0x7fffffffffffffffll; double eps = 1e-10; double pi = acos(-1.0); #define rep(i,s,n) for(int i=(s);i<=(n);++i) #define rep2(i,s,n) for(int i=(s);i>=(n);--i) #define mem(v,n) memset(v,(n),sizeof(v)) #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 int T,k; char s[100005]; int pq[100005]; ll caseNum[200]; ll b[100005]; int main(){ cin>>T; while(T--){ scanf("%s",s); scanf("%d",&k); int L=strlen(s); int head=1, tail=0; mem(caseNum,0); mem(b,0); b[0]=1; pq[++tail]=s[0]-'0'; caseNum[pq[tail]]++; rep(i,1,L-1){ pq[++tail]=s[i]-'0'; caseNum[pq[tail]]++; if(caseNum[pq[tail]]>k){ do{ caseNum[pq[head]]--; ++head; }while(caseNum[pq[tail]]>k); } b[i]=tail-head+1; } ll ans=0; rep(i,0,L-1) ans+=b[i]; printf("%I64d\n",ans); } }