ACM-ICPC 2018 焦作赛区网络预赛 H String and Times (后缀数组+容斥)

版权声明:欢迎转载,请注明此博客地址。 https://blog.csdn.net/Ever_glow/article/details/82717261

Now you have a string consists of uppercase letters, two integers A and B. We call a substring wonderful substring when the times it appears in that string is between A and B (A≤times≤B). Can you calculate the number of wonderful substrings in that string?

Input

Input has multiple test cases.

For each line, there is a string S, two integers A and B.

∑length(S)≤2×106,

1≤A≤B≤length(S)

Output

For each test case, print the number of the wonderful substrings in a line.

样例输入

AAA 2 3
ABAB 2 2

样例输出

2
3

后缀数组求出现K次不同字串的板子题,只需稍作修改,在容斥的时候,减去大于B次的就可以。
代码实现:

/*
Look at the star
Look at the shine for U
*/
#include<bits/stdc++.h>
#define ll long long
#define PII pair<int,int>
#define sl(x) scanf("%lld",&x)
using namespace std;
const int N = 200000+10;
int temp1[N],temp2[N],sam[N],c[N],lcp[N],num[N],Rank[N],len;
char s[N];
int dp[N][30];
 
void RMQ(int* arr, int n)
{
    for(int i = 0;i < n;++i) dp[i][0] = arr[i];
    for(int j = 1;(1<<j) <= n;++j)
    for(int i = 0;i+(1<<j)-1<n;++i)
    dp[i][j] = min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
 
ll ask(int l,int r)
{
    int k = 0;
    while((1<<(k+1))<=r-l+1) ++k;
    ll ans = min(dp[l][k],dp[r-(1<<k)+1][k]);
    return ans;
}

bool judge(int* arr,int x,int y,int l)
{
    if(arr[x] == arr[y] && arr[x+l] == arr[y+l]) return true;
    else return false;
}

ll query(int l,int r)
{
    if (l == r) return len-sam[r];
    return ask(l+1,r);
}

void init(int n,int m)
{
    ++n;
    int i,j,p,*x = temp1,*y = temp2;
    for(i = 0;i < m;++i) c[i] = 0;
    for(i = 0;i < n;++i) c[x[i] = num[i]]++;
    for(i = 1;i < m;++i) c[i] += c[i-1];
    for(i = n-1;i;--i) sam[--c[x[i]]] = i;
    for(j = 1;j <= n;j <<= 1)
	{
        p = 0;
        for(i = n-j; i<n;++i) y[p++] = i;
        for(i = 0;i < n;++i) 
		if(sam[i] >= j) 
		y[p++] = sam[i] - j;
        for(i = 0;i < m;++i) c[i] = 0;
        for(i = 0;i < n;++i) c[x[y[i]]]++;
        for(i = 1; i < m;++i) c[i] += c[i-1];
        for(i = n-1;i;--i) 
		sam[--c[x[y[i]]]] = y[i];
        swap(x,y);
        p = 1;
		x[sam[0]] = 0;
        for (i = 1;i < n;++i)
		{
			if(judge(y,sam[i-1],sam[i],j)) x[sam[i]] = p-1;
			else x[sam[i]] = p++;
		}
        if(p >= n) break;
        m = p;
    }
    int k = 0;
    n--;
    for(i = 0;i <= n;++i) Rank[sam[i]] = i;
    for(i = 0;i < n;++i)
	{
        if(k)--k;
        j = sam[Rank[i]-1];
        while(num[i+k] == num[j+k]) ++k;
        lcp[Rank[i]] = k;
    }
}

int main()
{
    int t,k,x,i,j;
    while(~scanf("%s%d%d",s,&k,&x))
	{
        len = strlen(s);
        for(i = 0;i <= len;i++)
        {
        	Rank[i] = lcp[i] = sam[i] = 0;
		}
        for (i = 0; i < len; ++i) num[i] = s[i]-'A'+1;
        num[len] = 0;
        init(len,30);
        RMQ(lcp,len+1);
        ll ans = 0;
        for (i = 1;i+k-1 <= len;i++)
		{
            ans += query(i,i+k-1);   //至少k个 
            if(i-1 > 0) ans -= query(i-1,i+k-1);
            if(i+x <= len) ans -= query(i,i+x);
            if(i-1 > 0 && i+x <= len) ans += query(i-1,i+x);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Ever_glow/article/details/82717261