1. 程式人生 > >BZOJ 3790 神奇項鏈 hash/後綴自動機+貪心

BZOJ 3790 神奇項鏈 hash/後綴自動機+貪心

space out 小寫字母 () 覆蓋 \n cdc tro led

Description

母親節就要到了,小 H 準備送給她一個特殊的項鏈。這個項鏈可以看作一個用小寫字母組成的字符串,每個小寫字母表示一種顏色。 為了制作這個項鏈,小 H 購買了兩個機器。第一個機器可以生成所有形式的回文串,第二個機器可以把兩個回文串連接起來,而且第二個機器還有一個特殊的性質:假如一個字符串的後綴和一個字符串的前綴是完全相同的,那麽可以將這個重復部分重疊。例如:aba和aca連接起來,可以生成串abaaca或 abaca。 現在給出目標項鏈的樣式,詢問你需要使用第二個機器多少次才能生成這個特殊的項鏈。

Input

輸入數據有多行,每行一個字符串,表示目標項鏈的樣式。

Output

多行,每行一個答案表示最少需要使用第二個機器的次數。

Sample Input

abcdcba
abacada
abcdef

Sample Output

0
2
5

HINT

每個測試數據,輸入不超過 5行,每行的字符串長度小於等於 50000。 分析: 回文串之間可以相互重疊,但是不妨礙辨認這些回文串,因此問題就變成了在給出的字符串中找到數量最少的回文串覆蓋整個字符串。 一個字符串看成一條線段,經典的貪心問題,只需要再求出每個點為中心的最長回文串即可進行貪心(小技巧是在字符串的間隔插上一個分隔符)。 最後用了二分+hash來求這個東西,想了想還可以用回文自動機把串倒著插進去來進行貪心。(bzoj不能用gets真的是太可怕了) 於是我把兩份代碼都拿出來了(滑稽)
 1
#include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cmath> 7 #include<queue> 8 #include<set> 9 #include<map> 10 #include<vector> 11 #include<cctype> 12 using namespace
std; 13 const int maxn=100005; 14 typedef long long LL; 15 const int mo=2100000007; 16 17 char S[maxn],T[maxn]; 18 int n,hash1[maxn],hash2[maxn],pw[maxn]; 19 struct data{ int l,r; }line[maxn]; 20 21 bool check(int i,int mid) 22 { 23 int v1=i-mid==0?hash1[i]:(hash1[i]-1ll*hash1[i-mid-1]*pw[mid+1]%mo+mo)%mo; 24 int v2=i+mid==n-1?hash2[i]:(hash2[i]-1ll*hash2[i+mid+1]*pw[mid+1]%mo+mo)%mo; 25 return v1==v2; 26 } 27 bool cmp(data x,data y){ return x.l<y.l||x.l==y.l&&x.r<y.r; } 28 void work() 29 { 30 n=strlen(T); 31 hash1[0]=T[0]-A+1; 32 for(int i=1;i<n;i++) hash1[i]=(hash1[i-1]*89ll+T[i]-A+1)%mo; 33 hash2[n-1]=T[n-1]-A+1; 34 for(int i=n-2;i>=0;i--) hash2[i]=(hash2[i+1]*89ll+T[i]-A+1)%mo; 35 for(int i=0;i<n;i++){ 36 int L=0,R=min(i,n-i-1)+1,mid,len=0; 37 while(L<R){ 38 mid=L+R>>1; 39 if(check(i,mid)) len=mid,L=mid+1; 40 else R=mid; 41 } 42 line[i]=(data){i-len,i+len}; 43 } 44 sort(line,line+n,cmp); 45 int ans=0,pos=0,mx=0; 46 for(int i=0;i<n;i++){ 47 if(line[i].l>pos) pos=mx,mx=0,ans++; 48 if(line[i].r>mx) mx=line[i].r; 49 } 50 printf("%d\n",max(0,ans-1)); 51 } 52 int main() 53 { 54 pw[0]=1; 55 for(int i=1;i<=100002;i++) pw[i]=pw[i-1]*89ll%mo; 56 while(scanf("%s",S)==1){ 57 int cnt=0; n=strlen(S); 58 T[cnt++]=A; 59 for(int i=0;i<n;i++) 60 T[cnt++]=S[i],T[cnt++]=A; 61 T[cnt]=\0; 62 work(); 63 } 64 return 0; 65 }

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<queue>
 8 #include<set>
 9 #include<map>
10 #include<vector>
11 #include<cctype>
12 #include<ctime>
13 using namespace std;
14 const int maxl=50005;
15 
16 char S[maxl];
17 int r[maxl];
18 struct PAM{
19     static const int maxn=50005;
20     int sz,last,to[maxn][26],len[maxn],fail[maxn],s[maxn],n;
21     int newnode(int l){
22         memset(to[sz],0,sizeof(to[sz]));
23         len[sz]=l,fail[sz]=0;
24         return sz++;
25     }
26     void init(){
27         sz=last=n=0;
28         newnode(0);newnode(-1);
29         s[0]=-1,fail[0]=1;
30     }
31     int getfail(int p){
32         while(s[n]!=s[n-len[p]-1]) p=fail[p];
33         return p;
34     }
35     void extend(int w){
36         s[++n]=w;
37         int p=getfail(last);
38         if(!to[p][w]){
39             int np=newnode(len[p]+2);
40             fail[np]=to[getfail(fail[p])][w];
41             to[p][w]=np;
42         }
43         last=to[p][w];
44     }
45 }pam;
46 
47 int main()
48 {
49     while(scanf("%s",&S)==1){
50         pam.init();
51         int n=strlen(S);
52         for(int i=n-1;i>=0;i--){
53             pam.extend(S[i]-a);
54             r[i]=i+pam.len[pam.last];
55         }
56         int pos=0,mx=0,ans=0;
57         for(int i=0;i<n;i++){
58             if(i>pos) pos=mx,mx=0,ans++;
59             if(r[i]>mx) mx=r[i];
60             if(i==n-1&&pos==n-1) ans++;
61         }
62         printf("%d\n",max(0,ans-1));
63     }
64     return 0;
65 }

BZOJ 3790 神奇項鏈 hash/後綴自動機+貪心