【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

 
原文地址:https://www.cnblogs.com/Konjakmoyu/p/5683570.html