zoukankan      html  css  js  c++  java
  • 【HDU3948】 The Number of Palindromes (后缀数组+RMQ)

    The Number of Palindromes

    Problem Description
    Now, you are given a string S. We want to know how many distinct substring of S which is palindrome.
    Input
    The first line of the input contains a single integer T(T<=20), which indicates number of test cases.
    Each test case consists of a string S, whose length is less than 100000 and only contains lowercase letters.
    Output
    For every test case, you should output "Case #k:" first in a single line, where k indicates the case number and starts at 1. Then output the number of distinct substring of S which is palindrome.
    Sample Input
    3
    aaaa
    abab
    abcd
    Sample Output
    Case #1: 4
    Case #2: 4
    Case #3: 4
     
     
    【题意】
      统计一个字符串内有多少个不同的回文串。
     
     
    【分析】
      这道题主要是去重。
      一开始我打的去重还是很有问题,还是看别人的才打出来了。
      
      把原串反向加入到原串后面,中间插入特殊字符。后缀数组求sa、height。
      分奇偶,奇串和偶串肯定是不同种的。然后对于一个位置i,找到对应位置,用rmq求区间min。
      去重:用cnt记录目前计算的回文长度与height的min值(所以这里计算的时候要按字符串大小顺序计算)。
      如果有新增回文串,就加进去,并更新cnt
     
      主要是最后一步,要好好理解。
     
    代码如下:
      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 #include<queue>
      7 using namespace std;
      8 #define Maxl 200010
      9 #define INF 0xfffffff
     10 
     11 int c[Maxl];
     12 int n,cl,l;
     13 
     14 int mymin(int x,int y) {return x<y?x:y;}
     15 int mymax(int x,int y) {return x>y?x:y;}
     16 
     17 char s[Maxl];
     18 void init()
     19 {
     20     scanf("%s",s);
     21     l=strlen(s);cl=0;
     22     for(int i=0;i<l;i++) c[++cl]=s[i]-'a'+1;
     23     c[++cl]=30;
     24     for(int i=l-1;i>=0;i--) c[++cl]=s[i]-'a'+1;
     25 }
     26 
     27 int sa[Maxl],rk[Maxl],Rs[Maxl],y[Maxl],wr[Maxl];
     28 void get_sa(int m)
     29 {
     30     memcpy(rk,c,sizeof(rk));
     31     for(int i=0;i<=m;i++) Rs[i]=0;
     32     for(int i=1;i<=cl;i++) Rs[rk[i]]++;
     33     for(int i=1;i<=m;i++) Rs[i]+=Rs[i-1];
     34     for(int i=cl;i>=1;i--) sa[Rs[rk[i]]--]=i;
     35     
     36     int ln=1,p=0;//p表示目前有多少个不一样的rk
     37     while(p<cl)
     38     {
     39         int k=0;
     40         for(int i=cl-ln+1;i<=cl;i++) y[++k]=i;
     41         for(int i=1;i<=cl;i++) if(sa[i]>ln) y[++k]=sa[i]-ln;
     42         for(int i=1;i<=cl;i++) 
     43             wr[i]=rk[y[i]];
     44         
     45         for(int i=0;i<=m;i++) Rs[i]=0;
     46         for(int i=1;i<=cl;i++) Rs[wr[i]]++;
     47         for(int i=1;i<=m;i++) Rs[i]+=Rs[i-1];
     48         for(int i=cl;i>=1;i--) sa[Rs[wr[i]]--]=y[i];
     49         
     50         for(int i=1;i<=cl;i++) wr[i]=rk[i];
     51         for(int i=cl+1;i<=cl+ln;i++) wr[i]=0;
     52         p=1,rk[sa[1]]=1;
     53         for(int i=2;i<=cl;i++)
     54         {
     55             if(wr[sa[i]]!=wr[sa[i-1]]||wr[sa[i]+ln]!=wr[sa[i-1]+ln]) p++;
     56             rk[sa[i]]=p;
     57         }
     58         ln*=2;m=p;
     59     }
     60     sa[0]=rk[0]=0;
     61 }
     62 
     63 int height[Maxl];
     64 void get_he()
     65 {
     66     int k=0;
     67     for(int i=1;i<=cl;i++) if(rk[i]!=1)
     68     {
     69         int j=sa[rk[i]-1];
     70         if(k) k--;
     71         while(c[i+k]==c[j+k]&&i+k<=cl&&j+k<=cl) k++;
     72         height[rk[i]]=k;
     73     }
     74     height[1]=0;
     75 }
     76 
     77 int d[Maxl][20];
     78 void rmq_init()
     79 {
     80     for(int i=1;i<=cl;i++) d[i][0]=height[i];
     81     for(int j=1;(1<<j)<=cl;j++)
     82       for(int i=1;i+(1<<j)-1<=cl;i++)
     83         d[i][j]=mymin(d[i][j-1],d[i+(1<<j-1)][j-1]);
     84 }
     85 
     86 int rmq(int x,int y)
     87 {
     88     int t;
     89     if(x>y) t=x,x=y,y=t;
     90     x++;
     91     int k=0;
     92     while((1<<(k+1))<=y-x+1) k++;
     93     return mymin(d[x][k],d[y-(1<<k)+1][k]);
     94 }
     95 
     96 
     97 int ans;
     98 void ffind()
     99 {
    100     int cnt=0;ans=0;
    101     //
    102     for(int i=1;i<=cl-n;i++)
    103     {
    104         cnt=mymin(cnt,height[i]);
    105         if(sa[i]<=l)
    106         {
    107             int j=rk[cl-sa[i]+1];
    108             int tem=rmq(i,j);
    109             if(tem>cnt)
    110             {
    111                 ans+=(tem-cnt);
    112                 cnt=tem;
    113             }
    114         }
    115     }
    116     //
    117     cnt=0;
    118      for(int i=1;i<=cl-n;i++)
    119      {
    120         cnt=mymin(cnt,height[i]);
    121         if(sa[i]<=l)
    122         {
    123             int j=rk[cl-sa[i]+2];
    124             int tem=rmq(i,j);
    125             if(tem>cnt)
    126             {
    127                 ans+=tem-cnt;
    128                 cnt=tem;
    129             }
    130         }
    131      }
    132 }
    133 
    134 int main()
    135 {
    136     int T,kase=0;
    137     scanf("%d",&T);
    138     while(T--)
    139     {
    140         init();
    141         get_sa(30+n);
    142         get_he();
    143         rmq_init();
    144         ffind();
    145         printf("Case #%d: %d
    ",++kase,ans);
    146     }
    147     return 0;
    148 }
    [HDU3948]

    2016-07-19 09:46:16

     
  • 相关阅读:
    简易计算机
    作业-继承
    exception
    作业-窗口
    作业-数字
    作业8
    作业9-1
    作业9-2
    book
    成绩录入
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/5683570.html
Copyright © 2011-2022 走看看