3439: Kpm的MC密码
Description
背景
想Kpm当年为了防止别人随便进入他的MC,给他的PC设了各种奇怪的密码和验证问题(不要问我他是怎么设的。。。),于是乎,他现在理所当然地忘记了密码,只能来解答那些神奇的身份验证问题了。。。
描述
Kpm当年设下的问题是这样的:
现在定义这么一个概念,如果字符串s是字符串c的一个后缀,那么我们称c是s的一个kpm串。
系统将随机生成n个由a…z组成的字符串,由1…n编号(s1,s2…,sn),然后将它们按序告诉你,接下来会给你n个数字,分别为k1…kn,对于每一个ki,要求你求出列出的n个字符串中所有是si的kpm串的字符串的编号中第ki小的数,如果不存在第ki小的数,则用-1代替。(比如说给出的字符串是cd,abcd,bcd,此时k1=2,那么”cd”的kpm串有”cd”,”abcd”,”bcd”,编号分别为1,2,3其中第2小的编号就是2)(PS:如果你能在相当快的时间里回答完所有n个ki的查询,那么你就可以成功帮kpm进入MC啦~~)
Input
第一行一个整数 n 表示字符串的数目
接下来第二行到n+1行总共n行,每行包括一个字符串,第i+1行的字符串表示编号为i的字符串
接下来包括n行,每行包括一个整数ki,意义如上题所示
Output
包括n行,第i行包括一个整数,表示所有是si的kpm串的字符串的编号中第ki小的数
Sample Input
3
cd
abcd
bcd
2
3
1
Sample Output
2
-1
2
样例解释
“cd”的kpm 串有”cd”,”abcd”,”bcd”,编号为1,2,3,第2小的编号是
2,”abcd”的kpm串只有一个,所以第3小的编号不存在,”bcd”的kpm
串有”abcd”,”bcd”,第1小的编号就是2。
数据范围与约定
设所有字符串的总长度为len
对于100%的数据,1<=n<=100000,0<len<=300000
-1
2
样例解释
“cd”的kpm 串有”cd”,”abcd”,”bcd”,编号为1,2,3,第2小的编号是
2,”abcd”的kpm串只有一个,所以第3小的编号不存在,”bcd”的kpm
串有”abcd”,”bcd”,第1小的编号就是2。
数据范围与约定
设所有字符串的总长度为len
对于100%的数据,1<=n<=100000,0<len<=300000
这道题非常容易想到把每个串翻转然后建立trie树,这样就把对于后缀的询问,转化成了在trie树上查询子树
然后可以用dfs序处理,再用可持久化线段树维护区间第k大值。。。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cmath> 4 #include<cstring> 5 #include<cstdio> 6 #include<algorithm> 7 #include<string> 8 #include<map> 9 #include<queue> 10 #include<vector> 11 #include<set> 12 #define inf 1000000000 13 #define maxn 300000+5 14 #define maxm 1000000+5 15 #define eps 1e-10 16 #define ll long long 17 #define for0(i,n) for(int i=0;i<=(n);i++) 18 #define for1(i,n) for(int i=1;i<=(n);i++) 19 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 20 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 21 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go) 22 using namespace std; 23 int read(){ 24 int x=0,f=1;char ch=getchar(); 25 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 26 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 27 return x*f; 28 } 29 int trie[maxn][26],o=1,fa[maxn]; 30 vector<int> en[maxn]; 31 int nx[100005],root[600005],lch[4*maxm],rch[4*maxm],num[4*maxm],x=0; 32 int dfn[maxn][2],now=0,n; 33 char a[300005]; 34 int insert(int i,int l,int r,int j){ 35 x++; 36 int t=x; 37 lch[t]=lch[i]; 38 rch[t]=rch[i]; 39 num[t]=num[i]+1; 40 if(l!=r){ 41 int mid=(l+r)>>1; 42 if(j>mid) rch[t]=insert(rch[i],mid+1,r,j); 43 else lch[t]=insert(lch[i],l,mid,j); 44 } 45 return t; 46 } 47 int dfs(int x){ 48 now++; 49 int sz=en[x].size(),rt=root[now-1]; 50 for0(i,sz-1) 51 rt=insert(rt,1,n,en[x][i]); 52 root[now]=rt; 53 dfn[x][0]=now; 54 for0(i,25) 55 if(trie[x][i]) 56 dfs(trie[x][i]); 57 now++; 58 dfn[x][1]=now; 59 root[now]=root[now-1]; 60 } 61 int get(int i,int j,int k){ 62 i=root[i-1],j=root[j]; 63 if(num[j]-num[i]<k) 64 return -1; 65 int l=1,r=n; 66 while(l!=r){ 67 int mid=(l+r)>>1; 68 if(num[lch[j]]-num[lch[i]]>=k){ 69 r=mid; 70 i=lch[i]; 71 j=lch[j]; 72 } 73 else{ 74 k-=num[lch[j]]-num[lch[i]]; 75 l=mid+1; 76 i=rch[i]; 77 j=rch[j]; 78 } 79 } 80 return l; 81 } 82 int main(){ 83 //freopen("input.txt","r",stdin); 84 //freopen("output.txt","w",stdout); 85 n=read(); 86 for1(i,n){ 87 scanf("%s",a); 88 int len=strlen(a); 89 for0(j,(len-2)/2) 90 swap(a[j],a[len-j-1]); 91 int p=1; 92 for0(j,len-1){ 93 if(trie[p][a[j]-'a']==0){ 94 o++; 95 trie[p][a[j]-'a']=o; 96 fa[o]=p; 97 } 98 p=trie[p][a[j]-'a']; 99 if(j==len-1){ 100 nx[i]=p; 101 en[p].push_back(i); 102 } 103 } 104 } 105 dfs(1); 106 for1(i,n){ 107 int x=read(); 108 printf("%d\n",get(dfn[nx[i]][0],dfn[nx[i]][1],x)); 109 } 110 return 0; 111 }