https://vjudge.net/problem/UVA-11107
题目
给n个字符串,每个字符串只由小写字母构成,求所有长度最长、在大于n/2个字符串中出现的字符串。如果有多个,按照字典序输出。
1<=n<=100,每个字符串不超过1000个字母。
时限6666ms
题解
不会做,书上提示用比较大的字符把这些字符串连接起来,然后求后缀数组和height数组,然后二分最大长度,将height>二分长度份的段,O(n)判断一下有多少种字符串,然后得到答案,时间复杂度O(nlogn)
然后问如何使用栈来做,然后我就按照栈来做了,写了很久,发现又慢又难写……大部分都是60ms AC,我交上去是70ms
可能是用了bitset才特别慢,但是我不想改了……
类似于单调栈,当遇到小于前一个height的时候,弹栈并计算字符串出现次数。由于出现的字符串编号是乱的,需要使用长度为100的bitset来统计
对height=0的后缀,只管弹栈,把这个编号放进下一个后缀,甚至可以所有后缀的编号都放进下一个后缀
然后就是慢慢调了
AC代码
#include<cstdio> #include<cstring> #include<algorithm> #include<bitset> using namespace std; #define MAXN 107 unsigned char s[MAXN*1000], id[MAXN*1000]; int sa[MAXN*1000], t1[MAXN*1000], t2[MAXN*1000], c[MAXN*1000], l, m; int rk[MAXN*1000], height[MAXN*1000], hid[MAXN*1000]; inline void calcsa() { int *x=t1, *y=t2; int now=0; for(int i=0; i<m; i++) c[i]=0; for(int i=0; i<l; i++) c[x[i]=s[i]-'a']++; for(int i=1; i<m; i++) c[i]+=c[i-1]; for(int i=l-1; i>=0; i--) sa[--c[x[i]]]=i; for(int k=1; k<=l; k<<=1) { int p=0; for(int i=l-k; i<l; i++) y[p++]=i; for(int i=0; i<l; i++) if(sa[i]>=k) y[p++]=sa[i]-k; for(int i=0; i<m; i++) c[i]=0; for(int i=0; i<l; i++) c[x[y[i]]]++; for(int i=1; i<m; i++) c[i]+=c[i-1]; for(int i=l-1; i>=0; i--) sa[--c[x[y[i]]]]=y[i]; swap(x,y); p=1; x[sa[0]]=0; for(int i=1; i<l; i++) { x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++; } if(p>=l) break; m=p; } for(int i=0; i<l; i++) rk[i]=x[i]; for(int i=0; i<l; i++) { if(s[i]>'z') now=s[i]-'z'; id[i]=now; } for(int i=0, k=0; i<l; i++) if(rk[i]) { if(k) k--; int j=sa[rk[i]-1]; while(i+k<l && j+k<l && s[i+k]==s[j+k]) k++; height[rk[i]]=k; } for(int i=0; i<l; i++) { hid[i]=id[sa[i]]; } } inline void putsn(char *s, int n) { while(0<n--) putchar((*(s++))); putchar(' '); } int sth[MAXN*1000], sz, stk[MAXN*1000]; bitset<100> stb[MAXN*1000], now; int n, ch=0, flg[MAXN*1000]; inline void solve_stack() { sz=0; //sth[0]=l+7; stb[0].reset(); stb[0].set(hid[0]); int ans=-1; bool ok=false; height[l]=0; for(int i=0; i<=l; i++) { // printf("*%d %d %d=%s", sa[i], hid[i], height[i], s+sa[i]); int ht=0x3f3f3f3f; now.reset(); if(sz>0) { int kk=stk[sz-1]; while(sz>0 && sth[sz-1]>height[i]) { if(ht<0x3f3f3f3f && ht>height[i]) { now.set(hid[stk[sz-1]]); if(now.count()>n/2) break; } now|=stb[sz-1]; ht=min(ht,sth[--sz]); } while(sz>0 && sth[sz-1]>height[i]) sz--; int nans=now.count(); if(nans>n/2) { ok=true; nans=ht; if(nans>ans) { ans=nans, flg[kk]=++ch; } else if(nans==ans) { flg[kk]=ch; } } } // printf(" %d ", now.count()); if(height[i]>0) { sth[sz]=height[i]; now.set(hid[i-1]); now.set(hid[i]); stb[sz]=now; stk[sz]=i; sz++; } } if(ok) { for(int i=1; i<l; i++) if(flg[i]==ch) { putsn((char*)s+sa[i], ans); } } else puts("?"); } int main() { bool fi=false; memset(flg,-1,sizeof flg); while(~scanf("%d", &n) && n) { if(fi) putchar(' '); else fi=true; char *p=(char*) s; m=26+n; for(int i=0; i<n; i++) { scanf("%s", p); int l=strlen(p); p+=l; *p=(unsigned)'z'+1+i; p++; } if(n==1) {*(--p)=0; puts((char*)s);continue;} *p=0; l=strlen((char*) s); calcsa(); solve_stack(); } }