【二分+字串hs】[POI2000] 公共串
阿新 • • 發佈:2019-01-01
題目描述 給出幾個由小寫字母構成的單詞,求它們最長的公共子串的長度。 任務: l 讀入單詞 l 計算最長公共子串的長度 l 輸出結果 輸入格式 檔案的第一行是整數 n,1<=n<=5,表示單詞的數量。接下來n行每行一個單詞,只由小寫字母組成,單詞的長度至少為1,最大為2000。 輸出格式 僅一行,一個整數,最長公共子串的長度。 樣例一 input 3 abcb bca acbc output 2 限制與約定 時間限制:1s1s 空間限制:256MBT
這道題看起來十分複雜,其實就是暴力二分長度
然後在第一個串中框一個這麼長的串去其他的裡面去驗證
程式碼在此
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define MA 2011 5 #define seed 1313131 6 using namespace std; 7 typedef unsigned long long ull; 8 int n,l=1,r=0x7f7f7f7f,ans; 9 char in[10][MA]; 10 int len[10]; 11 ull vv[10][MA],se[MA]; 12 inline bool check(int lenn) 13 { 14 for(int i=1;i+lenn-1<=len[1];i++) 15 { 16 int l=i,r=i+lenn-1; 17 int yeah=0; 18 ull val=vv[1][r]-vv[1][l-1]*se[lenn]; 19 for(int j=2;j<=n;j++) 20 { 21 int kk=0; 22 for(int k=1;k+lenn-1<=len[j];k++) 23 { 24 int ll=k,rr=k+lenn-1; 25 if(val==vv[j][rr]-vv[j][ll-1]*se[lenn]){kk=1;break;} 26 } 27 if(kk)yeah++; 28 } 29 if(yeah==n-1)return 1; 30 } 31 return 0; 32 } 33 int main() 34 { 35 scanf("%d",&n); 36 se[0]=1; 37 for(int i=1;i<MA;i++)se[i]=se[i-1]*seed; 38 for(int i=1;i<=n;i++) 39 { 40 scanf("%s",in[i]+1); 41 int ll=strlen(in[i]+1); 42 len[i]=ll,r=min(r,ll); 43 for(int j=1;j<=len[i];j++) 44 vv[i][j]=vv[i][j-1]*seed+in[i][j]; 45 } 46 while(l<=r) 47 { 48 int mid=(l+r)/2; 49 if(check(mid))l=mid+1,ans=mid; 50 else r=mid-1; 51 } 52 printf("%d\n",ans); 53 } 54 /* 55 4 56 alamakotaipsa 57 olamakotaikure 58 kotaipsa 59 ewamaswinkekotaipsa 60 */