1. 程式人生 > >【HDOJ5510】Bazinga(KMP)

【HDOJ5510】Bazinga(KMP)

題意:給定n個由小寫字母組成的字串,第i個字串為a[i],求最大的j滿足存在1<=i<j,a[i]不是a[j]的子串,無解輸出-1

T<=50,n<=500,len[i]<=2000

思路:隊友寫的,抱大腿

判斷某個串是否是另一個串的子串可以使用KMP

有一個優化:若a[i-1]是a[i]的子串,則將a[i-1]標記,後面不需要再列舉它

隊友的寫法是把連續一段縮成了一個

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define LL long long 
 4 const int maxn=505
; 5 char s[maxn][maxn<<2]; 6 int nxt[maxn][maxn<<2]; 7 int len[maxn]; 8 int p[maxn]; 9 void getnext(int x) 10 { 11 int i=0; int j=1; 12 nxt[x][1]=0; 13 int n=len[x]; 14 while(j<=n) 15 { 16 if(!i||s[x][i]==s[x][j]) 17 { 18 i++; j++; 19
nxt[x][j]=i; 20 } 21 else i=nxt[x][i]; 22 } 23 } 24 int kmp(int x,int y) 25 { 26 int i=1; int j=1; 27 int m=len[x]; 28 int n=len[y]; 29 while(j<=m) 30 { 31 if(!i||s[y][i]==s[x][j]) 32 { 33 i++; j++; 34 if(i>n)
35 { 36 return 1; 37 } 38 } 39 else i=nxt[y][i]; 40 } 41 return 0; 42 } 43 int main() 44 { 45 int T; 46 scanf("%d",&T); 47 int cas=0; 48 while(T--) 49 { 50 int n; 51 scanf("%d",&n); 52 memset(s,0,sizeof(s)); 53 for(int i=1;i<=n;i++) 54 { 55 scanf("%s",s[i]+1); 56 len[i]=strlen(s[i]+1); 57 getnext(i); 58 } 59 int g=0; 60 int num=0; 61 int r=n; 62 int l=0;; 63 for(int i=n;i>=2;i--) 64 { 65 if(!kmp(i,i-1)) 66 { 67 if(num==0) 68 { 69 l=i; 70 } 71 p[++num]=i-1; 72 } 73 } 74 printf("Case #%d: ",++cas); 75 if(!l) 76 printf("-1\n"); 77 else 78 { 79 for(int i=1;i<=num;i++) 80 { 81 for(int j=r;j>=l;j--) 82 { 83 if(!kmp(j,p[i])) 84 { 85 l=j; 86 break; 87 } 88 } 89 if(l==r) 90 break; 91 } 92 printf("%d\n",l); 93 } 94 } 95 }