其他分享
首页 > 其他分享> > 多次询问子串出现次数

多次询问子串出现次数

作者:互联网

hdu6599: here

南京manacher题:here

#pragma comment(linker, "/STACK:102400000,102400000")
#include<bits/stdc++.h>
#define fi first
#define se second
#define endl '\n'
#define o2(x) (x)*(x)
#define BASE_MAX 30
#define mk make_pair
#define eb emplace_back
#define all(x) (x).begin(), (x).end()
#define clr(a, b) memset((a),(b),sizeof((a)))
#define iis std::ios::sync_with_stdio(false); cin.tie(0)
#define my_unique(x) sort(all(x)),x.erase(unique(all(x)),x.end())
using namespace std;
#pragma optimize("-O3")
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> pii;
inline LL read() {
    LL x = 0;int f = 0;
    char ch = getchar();
    while (ch < '0' || ch > '9') f |= (ch == '-'), ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x = f ? -x : x;
}
inline void write(LL x, bool f) {
    if (x == 0) {putchar('0'); if(f)putchar('\n');else putchar(' ');return;}
    if (x < 0) {putchar('-');x = -x;}
    static char s[23];
    int l = 0;
    while (x != 0)s[l++] = x % 10 + 48, x /= 10;
    while (l)putchar(s[--l]);
    if(f)putchar('\n');else putchar(' ');
}
int lowbit(int x) { return x & (-x); }
template<class T>T big(const T &a1, const T &a2) { return a1 > a2 ? a1 : a2; }
template<typename T, typename ...R>T big(const T &f, const R &...r) { return big(f, big(r...)); }
template<class T>T sml(const T &a1, const T &a2) { return a1 < a2 ? a1 : a2; }
template<typename T, typename ...R>T sml(const T &f, const R &...r) { return sml(f, sml(r...)); }
void debug_out() { cerr << '\n'; }
template<typename T, typename ...R>void debug_out(const T &f, const R &...r) {cerr << f << " ";debug_out(r...);}
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]: ", debug_out(__VA_ARGS__);

#define print(x) write(x);

const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const int HMOD[] = {1000000009, 1004535809};
const LL BASE[] = {1572872831, 1971536491};
const int mod = 998244353;
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int MXN = 3e5 + 7;
const uLL base = 19260817;
char s[MXN];
int p[MXN], bin[22];
LL ANS[MXN];
uLL hs[MXN], bs[MXN];
inline uLL get_hash(int l, int r) {
    return hs[r] - hs[l-1]*bs[r-l+1];
}
unordered_map<uLL, int> ump;
int n;
struct Suffix_Automaton {
    static const int maxn = 3e5 + 105;
    static const int MAXN = 3e5 + 5;
    //basic
//    map<char,int> nex[maxn * 2];
    int nex[maxn*2][26];
    int link[maxn * 2], len[maxn * 2];
    int last, cnt;
    LL tot_c;//不同串的个数
    //extension
    int cntA[MAXN * 2], A[MAXN * 2];//辅助拓扑更新
    int nums[MAXN * 2];//每个节点代表的所有串的出现次数
    int dep[MAXN*2], pos[MAXN*2];
    void clear() {
        tot_c = 0;
        last = cnt = 1;
        link[1] = len[1] = 0;
//        nex[1].clear();
        memset(nex[1], 0, sizeof(nex[1]));
        for(int i = 0; i <= 2 * n + 1; ++i) nums[i] = 0;
    }
    void add(int c, int id) {
        int p = last, np = ++ cnt;
//        nex[cnt].clear();
        memset(nex[cnt], 0, sizeof(nex[cnt]));
        len[np] = len[p] + 1;
        nums[np] = 1;
        pos[id] = np;
        last = np;
        while (p && !nex[p][c])nex[p][c] = np, p = link[p];
        if (!p)link[np] = 1, tot_c += len[np] - len[link[np]];
        else {
            int q = nex[p][c];
            if (len[q] == len[p] + 1)link[np] = q, tot_c += len[np] - len[link[np]];
            else {
                int nq = ++cnt;
                len[nq] = len[p] + 1;
//                nex[nq] = nex[q];
                memcpy(nex[nq], nex[q], sizeof(nex[q]));
                link[nq] = link[q];
                link[np] = link[q] = nq;
                tot_c += len[np] - len[link[np]];
                while (nex[p][c] == q)nex[p][c] = nq, p = link[p];
            }
        }
    }
    void build(int n) {
//        memset(cntA, 0, sizeof cntA), memset(nums, 0, sizeof nums);
        for(int i = 0; i <= cnt; ++i) cntA[i] = 0;
        for (int i = 1; i <= cnt; i++)cntA[len[i]]++;
        for (int i = 1; i <= n; i++)cntA[i] += cntA[i - 1];
        for (int i = cnt; i >= 1; i--)A[cntA[len[i]]--] = i;
        //更行主串节点
//        int temps = 1;
//        for (int i = 1; i <= n; ++i) {
//            nums[temps = nex[temps][s[i] - 'a']] = 1;
//            debug(temps, s[i-1])
//        }
        //拓扑更新
        for (int i = cnt, x; i >= 1; i--) {
            //basic
            x = A[i];
            nums[link[x]] += nums[x];
        }
//        for(int i = 1; i <= cnt; ++i) debug(nums[i])
        for (int i = 1, t; i <= cnt; i++) {
            t = A[i];
            dep[t] = dep[link[t]] + 1;
            nex[t][0] = link[t];
//            for (int j = 1; bin[j] <= dep[t]; j++)
            for (int j = 1; j < 20; j++)
                if(bin[j] <= dep[t]) nex[t][j] = nex[nex[t][j - 1]][j - 1];
                else nex[t][j] = 0;
        }
    }
//    void DEBUG() {
//        for (int i = cnt; i >= 1; i--) {
//            printf("nums[%d]=%d numt[%d]=%d len[%d]=%d link[%d]=%d\n", i, nums[i], i, nums[i], i, len[i], i, link[i]);
//        }
//    }
    int query(int l, int r) {
        int mid = pos[r];
        for (int i = 19; i >= 0; i--) {
            int t = nex[mid][i];
            if (len[t] >= r - l + 1) mid = t;
        }
//        ans += siz[mid];
        ANS[r-l+1] += nums[mid];
//        debug(l, r, nums[mid])
    }
} sam;

void manacher() {
    int mx = 0, id;
    for (int i = 1; i <= n; i++) {
        if (mx > i)p[i] = min(mx - i, p[2 * id - i]);
        else p[i] = 0;
        while (s[i + p[i] + 1] == s[i - p[i]]) {
            if(ump.find(get_hash(i - p[i], i + p[i] + 1)) == ump.end()) {
                ump[get_hash(i - p[i], i + p[i] + 1)] = 1;
//                debug(gethash(i - p[i], i + p[i] + 1), i - p[i], i + p[i] + 1)
                int l = i - p[i], r = i + p[i] + 1;
                if(get_hash(l, (l+r)/2) == get_hash((l+r)/2+1, r)) {
                    sam.query(i - p[i], i + p[i] + 1);
                }
            }
            p[i]++;
        }
        if (p[i] + i > mx)mx = p[i] + i, id = i;
    }
    mx = 0;
    for (int i = 1; i <= n; i++) {
        if (mx > i)p[i] = min(mx - i - 1, p[2 * id - i]);
        else {
            p[i] = 1;
            if(ump.find(get_hash(i - p[i] + 1, i + p[i] - 1)) == ump.end()) {
                ump[get_hash(i - p[i] + 1, i + p[i] - 1)] = 1;
//                debug(gethash(i - p[i] + 1, i + p[i] - 1), i - p[i] + 1, i + p[i] - 1)
                int l = i - p[i] + 1, r = i + p[i] - 1;
                if(get_hash(l, (l+r)/2) == get_hash((l+r)/2, r)) {
                    sam.query(i - p[i] + 1, i + p[i] - 1);
                }
            }
        }
        while (s[i + p[i]] == s[i - p[i]]) {
            if(ump.find(get_hash(i - p[i], i + p[i])) == ump.end()) {
                ump[get_hash(i - p[i], i + p[i])] = 1;
//                debug(gethash(i - p[i], i + p[i]), i - p[i], i + p[i])
                int l = i - p[i], r = i + p[i];
                if(get_hash(l, (l+r)/2) == get_hash((l+r)/2, r)) {
                    sam.query(i - p[i], i + p[i]);
                }
            }
            p[i]++;
        }
        if (p[i] + i > mx)mx = p[i] + i, id = i;
    }
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("/home/cwolf9/CLionProjects/ccc/in.txt", "r", stdin);
    //freopen("/home/cwolf9/CLionProjects/ccc/out.txt", "w", stdout);
#endif
//    int tim = read();
    bin[0] = 1; bs[0] = 1;
    for (int i = 1; i < 20; i++) bin[i] = bin[i - 1] << 1;
    for(int i = 1;  i<= 300005; ++i) bs[i] = bs[i-1] * base;
    while (~scanf("%s", s + 1)) {
//        debug(s+1)
        n = strlen(s + 1);
        for(int i = 1; i <= n; ++i) hs[i] = hs[i-1] * base + s[i];
        sam.clear();
        ump.clear();
        for(int i = 0; i <= n + 2; ++i) p[i] = 0;
        for(int i = 1; i <= n; ++i) sam.add(s[i] - 'a', i), ANS[i] = 0;
        sam.build(n);
        manacher();
        for (int i = 1; i <= n; ++i) if (i == n) write(ANS[i], true); else write(ANS[i], false);
    }
#ifndef ONLINE_JUDGE
    cout << "time cost:" << clock() << "ms" << endl;
#endif
    return 0;
}
#pragma comment(linker, "/STACK:102400000,102400000")
#include<bits/stdc++.h>
#define fi first
#define se second
#define endl '\n'
#define o2(x) (x)*(x)
#define BASE_MAX 30
#define mk make_pair
#define eb emplace_back
#define all(x) (x).begin(), (x).end()
#define clr(a, b) memset((a),(b),sizeof((a)))
#define iis std::ios::sync_with_stdio(false); cin.tie(0)
#define my_unique(x) sort(all(x)),x.erase(unique(all(x)),x.end())
using namespace std;
#pragma optimize("-O3")
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> pii;
inline LL read() {
    LL x = 0;int f = 0;
    char ch = getchar();
    while (ch < '0' || ch > '9') f |= (ch == '-'), ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x = f ? -x : x;
}
inline void write(LL x, bool f) {
    if (x == 0) {putchar('0'); if(f)putchar('\n');else putchar(' ');return;}
    if (x < 0) {putchar('-');x = -x;}
    static char s[23];
    int l = 0;
    while (x != 0)s[l++] = x % 10 + 48, x /= 10;
    while (l)putchar(s[--l]);
    if(f)putchar('\n');else putchar(' ');
}
int lowbit(int x) { return x & (-x); }
template<class T>T big(const T &a1, const T &a2) { return a1 > a2 ? a1 : a2; }
template<typename T, typename ...R>T big(const T &f, const R &...r) { return big(f, big(r...)); }
template<class T>T sml(const T &a1, const T &a2) { return a1 < a2 ? a1 : a2; }
template<typename T, typename ...R>T sml(const T &f, const R &...r) { return sml(f, sml(r...)); }
void debug_out() { cerr << '\n'; }
template<typename T, typename ...R>void debug_out(const T &f, const R &...r) {cerr << f << " ";debug_out(r...);}
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]: ", debug_out(__VA_ARGS__);

#define print(x) write(x);

const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const int HMOD[] = {1000000009, 1004535809};
const LL BASE[] = {1572872831, 1971536491};
const int mod = 1e7 + 7;
const int MOD = 1e7 + 7;//998244353
const int INF = 0x3f3f3f3f;
const int MXN = 3e5 + 7;
const uLL base = 19260817;
char s[MXN];
int p[MXN], bin[22];
LL ANS[MXN];
uLL hs[MXN], bs[MXN];
unordered_map<uLL,bool> ump;
inline uLL get_hash(int l, int r) {
    return ((hs[r] - hs[l-1]*bs[r-l+1]));
}
int n;
//后缀数组(SA[i]存放排名第i大的后缀首字符的下标)
//名次数组(rank[i]存放Suffix(i)的优先级(名次))
//height数组:height[i]是Suffix(sa[i-1])和Suffix(sa[i])的最长公共前缀长度
//SA,R,H的下标都是 0~n 其中多包括了一个空字符串
struct Suffix_Array {
    static const int N = 3e5 + 7;
    int n, len, s[N], M;
    int sa[N], rnk[N], height[N];
    int tmp_one[N], tmp_two[N], c[N];
    int dp[N][21];
    void init_str(char *str, int _n) {
        len = _n;
        n = len + 1;
        for (int i = 0; i < len; ++i) s[i] = str[i];
        s[len] = '\0';
    }
    void build_sa(int m = 128);
    void calc_height(int n);
    void Out(char *str);
    void query(int l, int r);
    void RMQ_init(int n);
    int RMQ_query(int l, int r);
}sam;
void Suffix_Array::Out(char *str) {
    puts ("/*Suffix*/");
    for (int i=0; i<n; ++i) {
        printf ("%s\n", str+sa[i]);
    }
}
int Suffix_Array::RMQ_query(int l, int r) {//看自己需求自由变换
    int k = 0; while (1<<(k+1) <= r - l + 1) k++;
    return min(dp[l][k], dp[r-(1<<k)+1][k]);
}
void Suffix_Array::RMQ_init(int n) {
    for (int i=0; i<n; ++i) dp[i][0] = height[i];
    for (int j=1; (1<<j)<=n; ++j) {
        for (int i=0; i+(1<<j)-1<n; ++i) {
            dp[i][j] = std::min (dp[i][j-1], dp[i+(1<<(j-1))][j-1]);
        }
    }
}
void Suffix_Array::calc_height(int n) {
    for (int i=0; i<=n; ++i) rnk[sa[i]] = i;
    int k = height[0] = 0;
    for (int i=0; i<n; ++i) {
        if (k) k--;
        int j = sa[rnk[i]-1];
        while (s[i+k] == s[j+k]) k++;
        height[rnk[i]] = k;
    }
}
//m = max(r[i]) + 1,一般字符128足够了
void Suffix_Array::build_sa(int m) {
    int i, j, p, *x = tmp_one, *y = tmp_two;
    for (i=0; i<m; ++i) c[i] = 0;
    for (i=0; i<n; ++i) c[x[i]=s[i]]++;//此时第一关键字是x[i],第二关键字是i
    for (i=1; i<m; ++i) c[i] += c[i-1];
    for (i=n-1; i>=0; --i) sa[--c[x[i]]] = i;//排第几的后缀是i
    for (j=1; j<=n; j<<=1) {//y就是第二关键字从小到大的位置
        //y[i]表示第二关键字排名为i的数,第一关键字的位置
        for (p=0, i=n-j; i<n; ++i) y[p++] = i;//这些数的第二关键字为0
        for (i=0; i<n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j;//按rank顺序,1<<(j+1)的第二半的rank。sa[i]把自己交给了sa[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>=0; --i) sa[--c[x[y[i]]]] = y[i];//排第几的后缀是y[i]
        std::swap (x, y);
        for (p=1, x[sa[0]]=0, i=1; i<n; ++i) {//排完序后更新第一关键字
            x[sa[i]] = (y[sa[i-1]] == y[sa[i]] && y[sa[i-1]+j] == y[sa[i]+j] ? p - 1 : p++);
        }
        if(p >= n) break;
        m=p;
    }
    calc_height(n-1);
    RMQ_init(n);
}
void Suffix_Array::query(int l, int r) {
    -- l, -- r;
    int len = r - l + 1, L = 1, R = rnk[l]-1, mid, ans = -1;
    while(L <= R) {
        mid = (L + R) >> 1;
        if(RMQ_query(mid+1,  rnk[l]) >= len) ans = mid, R = mid - 1;
        else L = mid + 1;
    }
    int tmp = ans;
    L =  rnk[l] + 1, R = n - 1, ans = -1;
    while(L <= R) {
        mid = (L + R) >> 1;
        if(RMQ_query( rnk[l] + 1, mid) >= len) ans = mid, L = mid + 1;
        else R = mid - 1;
    }
    if(ans == -1 && tmp == -1) ANS[r-l+1] ++;
    else if(ans == -1) ANS[r-l+1] +=  rnk[l] - tmp + 1;
    else if(tmp == -1) ANS[r-l+1] += ans - rnk[l] + 1;
    else ANS[r-l+1] += ans - tmp + 1;
//    printf("%d %d %c %d %d %d\n", l, r, s[l],  rnk[l], ans, tmp);
}
void manacher() {
    int mx = 0, id;
    for (int i = 1; i <= n; i++) {
        if (mx > i)p[i] = min(mx - i, p[2 * id - i]);
        else p[i] = 0;
        while (s[i + p[i] + 1] == s[i - p[i]]) {
            if(ump.find(get_hash(i - p[i], i + p[i] + 1)) == ump.end()) {
                ump[get_hash(i - p[i], i + p[i] + 1)] = true;
                int l = i - p[i], r = i + p[i] + 1;
                if(get_hash(l, (l+r)/2) == get_hash((l+r)/2+1, r)) {
                    sam.query(i - p[i], i + p[i] + 1);
                }
            }
            p[i]++;
        }
        if (p[i] + i > mx)mx = p[i] + i, id = i;
    }
    mx = 0;
    for (int i = 1; i <= n; i++) {
        if (mx > i)p[i] = min(mx - i - 1, p[2 * id - i]);
        else {
            p[i] = 1;
            if(ump.find(get_hash(i - p[i] + 1, i + p[i] - 1)) == ump.end()) {
                ump[get_hash(i - p[i] + 1, i + p[i] - 1)] = true;
                int l = i - p[i] + 1, r = i + p[i] - 1;
                if(get_hash(l, (l+r)/2) == get_hash((l+r)/2, r)) {
                    sam.query(i - p[i] + 1, i + p[i] - 1);
                }
            }
        }
        while (s[i + p[i]] == s[i - p[i]]) {
            if(ump.find(get_hash(i - p[i], i + p[i])) == ump.end()) {
                ump[get_hash(i - p[i], i + p[i])] = true;
                int l = i - p[i], r = i + p[i];
                if(get_hash(l, (l+r)/2) == get_hash((l+r)/2, r)) {
                    sam.query(i - p[i], i + p[i]);
                }
            }
            p[i]++;
        }
        if (p[i] + i > mx)mx = p[i] + i, id = i;
    }
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("/home/cwolf9/CLionProjects/ccc/in.txt", "r", stdin);
    //freopen("/home/cwolf9/CLionProjects/ccc/out.txt", "w", stdout);
#endif
//    int tim = read();
    bin[0] = 1;
    for (int i = 1; i < 20; i++) bin[i] = bin[i - 1] << 1;
    bs[0] = 1;
    for(int i = 1;  i< MXN; ++i) bs[i] = (bs[i-1] * base);
    while (~scanf("%s", s + 1)) {
        n = strlen(s + 1);
        sam.init_str(s + 1, n);
        sam.build_sa();
//        for(int i = 0; i <= n; ++i) printf("%d ", sam.rnk[i]); printf("\n");
//        for(int i = 0; i <= n; ++i) printf("%d ", sam.sa[i]); printf("\n");
        for(int i = 1; i <= n; ++i) hs[i] = (hs[i-1] * base + s[i]);
        ump.clear();
        for(int i = 0; i <= n + 2; ++i) p[i] = 0;
        for(int i = 1; i <= n; ++i) ANS[i] = 0;
        manacher();
        for (int i = 1; i <= n; ++i) if (i == n) write(ANS[i], true); else write(ANS[i], false);
    }
#ifndef ONLINE_JUDGE
    cout << "time cost:" << clock() << "ms" << endl;
#endif
    return 0;
}

标签:子串,hash,ump,get,int,询问,次数,const,define
来源: https://www.cnblogs.com/Cwolf9/p/11253106.html