HDOJ 5769 Substring

来源:互联网 发布:逆袭网络宣传平台 编辑:程序博客网 时间:2024/05/12 09:28

题意

求一个字符串有多少个不同的子串,要求这些子串都包含至少一次x字符。

思路

如果不考虑包含x字符的话,求不同子串个数是一个后缀数组经典问题(spoj 694)。考虑那个问题的做法:leni=1lensa[i]lcp[i],len-sa[i]就是sa[i]开头的串的个数,再减去sa[i-1]时减过的lcp[i],累加起来就是答案了。然后这题直接只需要记录一下对每个下标i的后面最近出现x的位置nxt[i]是多少。然后在计算子串个数的时候不要计算nxt[i]之前的串就可以了。
我用之前那个题的代码改了一下结果TLE了。后来发现是板子的问题,挑战程序设计竞赛的板子使用的快排(出题人竟然卡这个。。话说这个板子A了很多题了这是第一次被卡= =
然后换成大白书上的过了。

代码

#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>#include <vector>#include <queue>#include <stack>#include <set>#include <map>#include <string>#include <math.h>#include <stdlib.h>#include <time.h>using namespace std;#define LL long long#define Lowbit(x) ((x)&(-x))#define lson l, mid, rt << 1#define rson mid + 1, r, rt << 1|1#define MP(a, b) make_pair(a, b)const int INF = 0x3f3f3f3f;const int MOD = 1000000007;const int maxn = 1e5 + 10;const double eps = 1e-8;const double PI = acos(-1.0);typedef pair<int, int> pii;//int temp[maxn], lcp[maxn];char x[2];char str[maxn];int nxt[maxn];int sa[maxn], rk[maxn], height[maxn];int c[maxn], t[2][maxn], s[maxn];void build(int n, int m) {    int i, k, p, *x = t[0], *y = t[1];    memset(c, 0, m << 2);    for(i = 0; i < n; ++i) ++c[x[i] = s[i]];    for(i = 1; i < m; ++i) c[i] += c[i - 1];    for(i = n - 1; i >= 0; --i) sa[--c[x[i]]] = i;    for(k = 1; k <= n; k <<= 1) {        p = 0;        for(i = n - k; i < n; ++i) y[p++] = i;        for(i = 0; i < n; ++i) if(sa[i] >= k) y[p++] = sa[i] - k;        memset(c, 0, m << 2);        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 >= 0; --i) sa[--c[x[y[i]]]] = y[i];        swap(x, y); p = 1; x[sa[0]] = 0;        for(i = 1; i < n; ++i)            x[sa[i]] = (y[sa[i - 1]] == y[sa[i]] &&                        y[sa[i - 1] + k] == y[sa[i] + k]) ? p - 1 : p++;        if(p >= n) break; m = p;    }    for(i = 0; i < n; ++i) rk[sa[i]] = i;    for(i = 0, k = 0; i < n; ++i) {        if(k) k--;        if(!rk[i]) continue;        int j = sa[rk[i] - 1];        while(s[i + k] == s[j + k]) k++;        height[rk[i]] = k;    }}//int compare_sa(int i, int j)//{//    if (rk[i] != rk[j]) return rk[i] < rk[j];//    else//    {//        int ri = i + k <= n ? rk[i+k] : -1;//        int rj = j + k <= n ? rk[j+k] : -1;//        return ri < rj;//    }//}////void construct_sa(char *s, int *sa)//{//    for (int i = 0; i <= n; i++)//    {//        sa[i] = i;//        rk[i] = i < n ? s[i] : -1;//    }//    for (k = 1; k <= n; k *= 2)//    {//        sort(sa, sa + n + 1, compare_sa);//        temp[s[0]] = 0;//        for (int i = 1; i <= n; i++)//            temp[sa[i]] = temp[sa[i-1]] + (compare_sa(sa[i-1], sa[i]) ? 1 : 0);//        for (int i = 0; i <= n; i++)//            rk[i] = temp[i];//    }//}////void construct_lcp(char *s, int *sa, int *lcp)//{//    for (int i = 0; i <= n; i++) rk[sa[i]] = i;//    int h = 0;//    lcp[0] = 0;//    for (int i = 0; i < n; i++)//    {//        int j = sa[rk[i] - 1];//        if (h > 0) h--;//        for (; j + h < n && i + h < n; h++)//            if (s[j+h] != s[i+h]) break;//        lcp[rk[i] - 1] = h;//    }//}int main(){    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    int T;    scanf("%d", &T);    for (int ncase = 1; ncase <= T; ncase++)    {        scanf("%s%s", x, str);        int n = strlen(str);        for (int i = 0; i < n; i++) s[i] = str[i] - 'a' + 1;        s[n] = 0;        build(n + 1, 30);        nxt[n] = n;        for (int i = n - 1; i >= 0; i--)        {            nxt[i] = nxt[i+1];            if (str[i] == x[0]) nxt[i] = i;        }        LL ans = 0;        for (int i = 1; i <= n; i++)        {            //printf("%d %d %d %d\n", i, sa[i], height[i], nxt[sa[i]]);            ans += n - max(sa[i] + height[i], nxt[sa[i]]);        }        printf("Case #%d: %lld\n", ncase, ans);    }    return 0;}
0 0