bzoj3448[Usaco2014 Feb]Auto-complete*
bzoj3448[Usaco2014 Feb]Auto-complete
题意:
给个字符串集,询问字符串集中以字符串s为前缀的第k小字符串编号多少。字符串集总长度≤3000000,询问数≤1000,询问字符串长度≤1000。
题解:
先吐槽一下bzoj:自己加强了数据也不说一声,明明字符串集总长度不只1000000,不过我也不知道是不是3000000,反正2000000会RE。
一看到字符串集,以为是trie,结果又MLE又TLE,改左兄弟右儿子表示法又写炸。看题解trie求DFS序然后用主席树维护……天啊怎么银组题也这么劲QAQ。后来受神犇ccz受教,原来只要先给字符串集排序,然后二分找区间就行了,usaco题解也是这样写的。写完了结果re无数次,本机测usaco数据什么事也没有,最后一怒之下数组开到3000000,过了~注意因为只给出字符串集总长度不知道字符串个数,所以字符串要用一个链表维护。(然而正常人都是用STLstring不会RE不说代码还比我少一半,我太弱了QAQ)
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define maxn 3000010 5 #define inc(i,j,k) for(int i=j;i<=k;i++) 6 using namespace std; 7 8 inline int read(){ 9 char ch=getchar(); int f=1,x=0; 10 while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} 11 while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); 12 return f*x; 13 } 14 struct hd{int nx,id;}; hd hds[maxn]; 15 struct nd{char ch; int nx;}; nd nds[maxn]; int ndss; 16 bool cmp(hd a,hd b){ 17 int j=a.nx,k=b.nx; 18 while(j&&k){ 19 if(nds[j].ch<nds[k].ch)return 1; 20 if(nds[j].ch>nds[k].ch)return 0; 21 j=nds[j].nx; k=nds[k].nx; 22 } 23 if(!j&&!k)return a.id<b.id; 24 if(!j)return 1;else return 0; 25 } 26 int w,n; char str[maxn]; 27 int check(int x){ 28 x=hds[x].nx; int len=strlen(str+1); 29 for(int i=1;i<=len;i++,x=nds[x].nx){ 30 if(!x||str[i]>nds[x].ch)return 1; 31 if(str[i]<nds[x].ch)return -1; 32 } 33 return 0; 34 } 35 int main(){ 36 w=read(); n=read(); 37 inc(i,1,w){ 38 char ch=getchar(); while(ch<'a'||ch>'z')ch=getchar(); 39 hds[i]=(hd){++ndss,i}; 40 while(ch>='a'&&ch<='z') 41 nds[ndss]=(nd){ch,ndss+1},ndss++,ch=getchar(); 42 nds[--ndss].nx=0; 43 } 44 sort(hds+1,hds+1+w,cmp); 45 inc(i,1,n){ 46 int k=read(); scanf("%s",str+1); 47 int q=-1,l=1,r=w; 48 while(l<=r){ 49 int mid=(l+r)>>1; int c=check(mid); 50 if(c==0)q=mid,r=mid-1; 51 else if(c==-1)r=mid-1;else l=mid+1; 52 } 53 if(q==-1||q+k-1>w||check(q+k-1)!=0)printf("-1\n"); 54 else printf("%d\n",hds[q+k-1].id); 55 } 56 return 0; 57 }
20160824