zoukankan      html  css  js  c++  java
  • bzoj4516 [Sdoi2016]生成魔咒

      后缀数组,首先先将数组反转,从后往前做,此时的后缀就等于是原串的前缀,那么每添加一个前缀,增加了多少个不同的子串,其实就是在之前添加的前缀中,排名最靠近该前缀的两个串a和b,计算出他们与该前缀的lcp,然后不同的子串数就是当前添加的前缀长度len-max(lcpa,lcpb)了。具体实现维护排名可以用一个set维护,复杂度O(nlogn)。

      代码

      

      1  #include <cstdio>
      2 #include <cstring>
      3 #include<map>
      4 #include<set>
      5 using namespace std;
      6 const int L = 110;
      7 const int N = 1010;
      8 
      9 const int MAXN =  N*L;       //数列的最大值和个数上界
     10 
     11 struct SuffixArray{
     12     int wa[MAXN];            //用来进行基数排序或临时变量
     13     int wb[MAXN];            //用来进行基数排序或临时变量
     14     int wv[MAXN];            //用来进行基数排序或临时变量
     15     int ws[MAXN];            //用来进行基数排序或临时变量
     16 
     17     int sa[MAXN];            //sa[i]代表排名为i的后缀在原数列起始下标(数列的下标从0开始),sa[0]肯定等于n,因为标兵为最小的。
     18     int rank[MAXN];          //rank[i]代表suffix[i]的排名,rank[n]肯定等于0,理由同上。
     19     int height[MAXN];        //height[i]代表排名为i - 1的后缀 和排名为i的后缀 的最长公共连续子序列 的长度。
     20     int r[MAXN];             //r[]存放原数列下标从0到n,r[n]为a标兵,是r[]里面最小的.
     21     int n;                   //数列的元素个数,不包括标兵
     22     int m;                   //存放最大值,r[]数组的数都要小于m,用来进行基数排序
     23 
     24     void input(int *val, int len, int Max){//Max要大于r[0..len - 1],因为内部采用了基数排序
     25         for (int i = 0;i < len;i++)
     26             r[i] = val[i];
     27         r[len] = 0;                        //最小值,起标兵作用
     28         n = len;
     29         m = Max;
     30         calSa();
     31         calHeight();
     32     }
     33 
     34     int cmp(int *r, int a, int b, int l){
     35         return (r[a] == r[b] && r[a + l] == r[b + l]);
     36     }
     37 
     38     void calSa(){                  //求sa数组
     39         int i, j, p, *x = wa, *y = wb, *t;
     40         for (i = 0;i < m;i++) ws[i] = 0;
     41         for (i = 0;i < n + 1;i++) ws[x[i] = r[i]]++;
     42         for (i = 1;i < m;i++) ws[i] += ws[i - 1];
     43         for (i = n;i >= 0;i--) sa[--ws[x[i]]] = i;
     44         for (j = 1, p = 1;p < n + 1;j *= 2, m = p){
     45             for (p = 0, i = n - j + 1;i < n + 1;i++) y[p++] = i;
     46             for (i = 0;i < n + 1;i++) if (sa[i] >= j) y[p++] = sa[i] - j;
     47             for (i = 0;i < n + 1;i++) wv[i] = x[y[i]];
     48             for (i = 0;i < m;i++) ws[i] = 0;
     49             for (i = 0;i < n + 1;i++) ws[wv[i]]++;
     50             for (i = 1;i < m;i++) ws[i] += ws[i - 1];
     51             for (i = n;i >= 0;i--) sa[--ws[wv[i]]] = y[i];
     52             for (t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n + 1;i++)
     53                 x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p - 1 : p++;
     54         }
     55     }
     56 
     57     void calHeight(){               //求rank和height数组
     58         int i, j, k = 0;
     59         for (i = 1;i <= n;i++) rank[sa[i]] = i;
     60         for (i = 0;i < n;height[rank[i++]] = k)
     61             for (k?k--:0, j = sa[rank[i]- 1];r[i + k] == r[j + k];k++);
     62     }
     63     //-求任意两后缀最长公共前缀问题,如果没用到可以去掉----------------------
     64     int Log[MAXN];
     65     int best[20][MAXN];
     66     void initRMQ() {             //初始化RMQ 标准RMQ 预处理O(nlgn)
     67         Log[0] = -1;
     68         for(int i = 1;i <= MAXN;i++){
     69             Log[i]=(i & (i - 1))?Log[i - 1] : Log[i - 1] + 1 ;
     70         }
     71         for(int i = 1; i <= n ; i ++) best[0][i] = height[i];
     72         for(int i = 1; i <= Log[n] ; i ++) {
     73             int limit = n - (1<<i) + 1;
     74             for(int j = 1; j <= limit ; j ++) {
     75                 best[i][j] = (best[i-1][j] > best[i-1][j+(1<<i>>1)]) ? best[i-1][j+(1<<i>>1)] : best[i-1][j];
     76             }
     77         }
     78     }
     79     int lcp(int a,int b) {       //询问suffix[a]于suffix[b]的最长公共前缀(标准RMQ  询问O(1))  使用这个函数之前要先后调用initRMQ()和input()
     80         if(a > b){
     81             int t = a;
     82             a = b;
     83             b = t;
     84         }
     85         a ++;
     86         int t = Log[b - a + 1];
     87         return (best[t][a] > best[t][b - (1<<t) + 1])? best[t][b - (1<<t) + 1] : best[t][a];
     88     }
     89 }SA;
     90 int n,i,a[MAXN],m,u,v,tot,len,t,tmp;
     91 long long ans;
     92 map<int,int> ma;
     93 set<int> s;
     94 set<int>::iterator it;
     95 int main()
     96 {
     97     scanf("%d",&n);
     98     for (i=0;i<n;i++)
     99     {
    100         scanf("%d",&a[i]);
    101         if (ma[a[i]]==0) ma[a[i]]=++tot;
    102         a[i]=ma[a[i]];
    103     }
    104     for (i=0;i<n-1-i;i++)
    105     {
    106         t=a[i];a[i]=a[n-1-i];a[n-1-i]=t;
    107     }
    108     SA.input(a,n,tot+10);
    109     SA.initRMQ();
    110     for (i=n-1;i>=0;i--)
    111     {
    112         len=n-i;tmp=0;
    113         it=s.upper_bound(SA.rank[i]);
    114         if (it!=s.end()) tmp=max(tmp,SA.lcp(*it,SA.rank[i]));
    115         if (it!=s.begin()) tmp=max(tmp,SA.lcp(*(--it),SA.rank[i]));
    116         s.insert(SA.rank[i]);
    117         ans=ans+len-tmp;
    118         printf("%lld
    ",ans);
    119     }
    120     
    121 }
  • 相关阅读:
    Blend操作入门: 别站在门外偷看,快进来吧!
    Egyee,这个世界很美丽
    在Windows Azure中使用自己的域名
    Windows Azure服务购买,收费,使用注意事项及学习资料推荐
    Silverlight怎样加载xap中的各个程序集
    WCF RIA Service随想
    Silverlight布局,也许不止这么多(附照片墙示例及源码)
    An introduction to variable and feature selection
    Compressed Learning
    Robust PCA (摘抄)
  • 原文地址:https://www.cnblogs.com/fzmh/p/5426183.html
Copyright © 2011-2022 走看看