zoukankan      html  css  js  c++  java
  • hdu5769--Substring(后缀数组)

    题意:求含有某个字母的某个字符串的不同子串的个数

    题解:后缀数组,因为不太了解后缀模版卡了一会,还是很简单的。

    把后缀按照字典序排序后,一定是取每个后缀的一些前缀,如果两个后缀排名相邻,那么它们的前缀一定是相同的,height数组纪录,那么就不用重复考虑了。同时要记录里每个字母向后最近的需要出现的字符出现的位置,所取前缀至少要包含这个字母。

    记住sa和height数组都是1-n的下标。

    //后缀数组
    #include <stdio.h>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    
    const int N = int(2e5)+10;
    int cmp(int *r,int a,int b,int l){
        return (r[a]==r[b]) && (r[a+l]==r[b+l]);
    }
    // 用于比较第一关键字与第二关键字,
    // 比较特殊的地方是,预处理的时候,r[n]=0(小于前面出现过的字符)
    
    int wa[N],wb[N],wss[N],wv[N];
    int sa[N];        // 排第几的是谁 1~n
    int rk[N],     // 谁排第几       
        height[N];    // 排名相邻的两个后缀的最长公共前缀长度:suffix(sa[i-1])和(sa[i]) 的最长公共前缀,
    char str[N];
    int p[N];
    
    void DA(char *r,int *sa,int n,int m){                    // 此处N比输入的N要多1,为人工添加的一个字符,用于避免CMP时越界
        int i,j,p,*x=wa,*y=wb,*t;
        for(i=0;i<m;i++) wss[i]=0;
        for(i=0;i<n;i++) wss[x[i]=r[i]]++;
        for(i=1;i<m;i++) wss[i]+=wss[i-1];
        for(i=n-1;i>=0;i--) sa[--wss[x[i]]]=i;
        for(j=1,p=1;p<n;j*=2,m=p)
        {
            for(p=0,i=n-j;i<n;i++) y[p++]=i;
            for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
            for(i=0;i<n;i++) wv[i]=x[y[i]];
            for(i=0;i<m;i++) wss[i]=0;
            for(i=0;i<n;i++) wss[wv[i]]++;
            for(i=1;i<m;i++) wss[i]+=wss[i-1];
            for(i=n-1;i>=0;i--) sa[--wss[wv[i]]]=y[i];
            for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
                x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
        }
    }
    
    void calheight(char *r,int *sa,int n){                    // 此处N为实际长度
        int i,j,k=0;                    
        for(i=1;i<=n;i++) rk[sa[i]]=i;
        for(i=0;i<n; height[rk[i++]] = k )
        for(k?k--:0,j=sa[rk[i]-1]; r[i+k]==r[j+k]; k++);
    }
    
    
    int main(int argc, char const *argv[])
    {
        //freopen("in", "r", stdin);
        int T;
        cin >> T;
        int cas = 0;
        while (T--) {
            printf("Case #%d: ", ++cas);
            char tmp[10];
            char x;
            scanf("%s%s", tmp, str);
            x = *tmp;
            getchar();
            int pos = -1;
            int n = strlen(str);
            for (int i = n-1; i >= 0; --i) {
                if (str[i] == x) pos = i;
                p[i] = pos;
            }
            DA(str, sa, n+1, 200);
            calheight(str, sa, n);
            ll ans = 0;
            if (p[ sa[1] ] != -1) ans += n - p[ sa[1] ];
            for (int i = 2; i <= n; ++i) {
                int now = sa[i];
                int l = max(now+height[i], p[now]);
                if (p[now] == -1) continue;
                ans += n - l;
            }
            cout << ans << endl;
        }
        return 0;
    }
  • 相关阅读:
    POJ 3616 Milking Time(简单DP)
    POJ 2954 Triangle(计算几何Pick定理)
    POJ 3664 Election Time(简单的快速排序)
    POJ 2007 Scrambled Polygon(计算几何凸包)
    POJ 3673 Cow Multiplication(简单数学)
    POJ 3663 Costume Party (快速排序)
    计算几何模板(一)
    [转]Silverlight中使用MVVM(3)
    Silverlight中使用MVVM(2)
    Silverlight使用Binding动态绑定数据
  • 原文地址:https://www.cnblogs.com/wenruo/p/5722043.html
Copyright © 2011-2022 走看看