HDU 5510 Bazinga
阿新 • • 發佈:2018-09-03
std 代碼 inpu namespace mem open stdin inline ++
1. 筆記
思路是:首先從前到後掃一遍,如果一個字符串不是後一個字符串的字串就把它標記一下(表示之後不會再掃它);再從後到前來看,很容易想到,如果從k到n都被未被標記過,而k-1被標記過,那麽答案肯定是[k,n]裏的一個數(當然,輸出-1當且僅當k==1)。另外,如果答案是ans,那麽[k,ans]都滿足條件,(ans,n]都不滿足條件。
我看網上很多題解都是從暴力從n掃到1,甚至還有用strstr也A的。但k=n/2時復雜度是\(O(n^2l)\)。保險起見我用KMP+二分,復雜度是\(O(nlognl)\)。
2. 代碼
#include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=a;i<=b;++i) #define ms(arr,a) memset(arr,a,sizeof arr) #define debug(x) cout<<"< "#x" = "<<x<<" >"<<endl const int maxP=2005; int f[maxP]; void get_fail(char P[]) { int l=strlen(P); f[0]=f[1]=0; for(int i=1,j;i<l;++i) { j=f[i]; while(j&&P[i]!=P[j])j=f[j]; f[i+1]=P[i]==P[j]?j+1:0; } } char* kmp(char T[],char P[]) { get_fail(P); int lT=strlen(T),lP=strlen(P); for(int i=0,j=0;i<lT;++i) { while(j&&T[i]!=P[j])j=f[j]; if(T[i]==P[j])++j; if(j==lP)return T+(i-lP+1); } return NULL; } int n; char s[505][2005]; int mark[505]={0}; bool ok(int m) { for(int i=mark[m];i;) { if(!kmp(s[m],s[i]))return true; if(mark[i]==i)i--; else i=mark[i]; } return false; } int bs(int l,int r) { int m;bool okl=ok(l),okr=ok(r); if(okl&&okr)return r; if(!okl&&!okr)return -1; if(!okl){r=r^l;l=r^l;r=r^l;} while(r-l>1||l-r>1) { m=(l+r)/2; if(ok(m))l=m; else r=m; } return l; } int main() { //freopen("Input.txt","r",stdin); int T;scanf("%d",&T); for(int Case=1;Case<=T;++Case) { scanf("%d",&n); rep(i,1,n)scanf("%s",s+i); rep(i,1,n-1)mark[i]=kmp(s[i+1],s[i])?mark[i-1]:i;mark[n]=mark[n-1]; //rep(i,1,n)printf("%d ",mark[i]);printf("\n"); printf("Case #%d: %d\n",Case,bs(mark[n-1]+1,n));// } }
HDU 5510 Bazinga