BZOJ3439: Kpm的MC密码
3439: Kpm的MC密码
Time Limit: 15 Sec Memory Limit: 256 MBSubmit: 166 Solved: 79
[Submit][Status]
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
HINT
Source
题解:
真是一道好题!
很容易想到把字符串反转之后插入一棵trie树,然后s的kpm串就是它的子树,然后dfs序处理一下把子树内的信息变成连续的就可以用主席树求第k小了。
刚开始把kpm串的定义看反了,然后就把每个点到根节点的主席树建了出来。。。
实现的时候有很多细节,我参考了某大牛的代码
代码:
1 #include<cstdio> 2 #include<cstdlib> 3 #include<iostream> 4 #include<algorithm> 5 #include<cstring> 6 #include<queue> 7 #include<vector> 8 #include<map> 9 #include<set> 10 #include<stack> 11 #include<string> 12 #include<cmath> 13 #include<cctype> 14 using namespace std; 15 const int maxlongint=2147483647; 16 const int inf=1000000000; 17 int trie[300010][26],o=1,fa[300010]; 18 vector<int> en[300010]; 19 int nx[100010]; 20 char a[300010]; 21 int root[600010]; 22 int lch[4000010],rch[4000010],num[4000010],x=0; 23 int dfn[300010][2],now=0,n; 24 int insert(int i,int l,int r,int j) 25 { 26 x++; 27 int t=x; 28 lch[t]=lch[i]; 29 rch[t]=rch[i]; 30 num[t]=num[i]+1; 31 if(l!=r) 32 { 33 int mid=(l+r)>>1; 34 if(j>mid) 35 rch[t]=insert(rch[i],mid+1,r,j); 36 else 37 lch[t]=insert(lch[i],l,mid,j); 38 } 39 return t; 40 } 41 int dfs(int i) 42 { 43 int n1; 44 now++; 45 int sz=en[i].size(),rt=root[now-1]; 46 for(n1=0;n1<sz;n1++) 47 rt=insert(rt,1,n,en[i][n1]); 48 root[now]=rt; 49 dfn[i][0]=now; 50 for(n1=0;n1<26;n1++) 51 if(trie[i][n1]) 52 dfs(trie[i][n1]); 53 now++; 54 dfn[i][1]=now; 55 root[now]=root[now-1]; 56 } 57 int get(int i,int j,int k) 58 { 59 i=root[i-1],j=root[j]; 60 if(num[j]-num[i]<k) 61 return -1; 62 int l=1,r=n; 63 while(l!=r) 64 { 65 int mid=(l+r)>>1; 66 if(num[lch[j]]-num[lch[i]]>=k) 67 { 68 r=mid; 69 i=lch[i]; 70 j=lch[j]; 71 } 72 else 73 { 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 { 84 int n1,n2; 85 cin>>n; 86 for(n1=1;n1<=n;n1++) 87 { 88 scanf("%s",a); 89 int len=strlen(a); 90 for(n2=0;n2<=(len-2)/2;n2++) 91 swap(a[n2],a[len-n2-1]); 92 int p=1; 93 for(n2=0;n2<len;n2++) 94 { 95 if(trie[p][a[n2]-97]==0) 96 { 97 o++; 98 trie[p][a[n2]-97]=o; 99 fa[o]=p; 100 } 101 p=trie[p][a[n2]-97]; 102 if(n2==len-1) 103 { 104 nx[n1]=p; 105 en[p].push_back(n1); 106 } 107 } 108 } 109 dfs(1); 110 int t1; 111 for(n1=1;n1<=n;n1++) 112 { 113 scanf("%d",&t1); 114 printf("%d\n",get(dfn[nx[n1]][0],dfn[nx[n1]][1],t1)); 115 } 116 }
我的:TLE
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<iostream> 7 #include<vector> 8 #include<map> 9 #include<set> 10 #include<queue> 11 #include<string> 12 #define inf 1000000000 13 #define maxn 1000000+5 14 #define maxm 5000000 15 #define eps 1e-10 16 #define ll long long 17 #define pa pair<int,int> 18 #define for0(i,n) for(int i=0;i<=(n);i++) 19 #define for1(i,n) for(int i=1;i<=(n);i++) 20 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 21 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 22 #define mod 1000000007 23 using namespace std; 24 inline int read() 25 { 26 int x=0,f=1;char ch=getchar(); 27 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 28 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 29 return x*f; 30 } 31 int n,m,cnt=1,tot,now,s[maxm],ls[maxm],rs[maxm],t[maxn][26],rt[maxn],dfn[maxn][2],p[maxn]; 32 vector<int>G[maxn]; 33 char st[maxn]; 34 void update(int l,int r,int x,int &y,int z) 35 { 36 y=++tot; 37 s[y]=s[x]+1; 38 if(l==r)return; 39 ls[y]=ls[x];rs[y]=rs[x]; 40 int mid=(l+r)>>1; 41 if(z<=mid)update(l,mid,ls[x],ls[y],z);else update(mid+1,r,rs[x],rs[y],z); 42 } 43 void dfs(int x) 44 { 45 dfn[x][0]=++now; 46 int sz=G[x].size(),y=rt[now-1],yy=y; 47 for0(i,sz-1)update(1,n,y,yy,G[x][i]),y=yy; 48 rt[now]=yy; 49 for0(i,25)if(t[x][i])dfs(t[x][i]); 50 dfn[x][1]=++now; 51 rt[now]=rt[now-1]; 52 } 53 int query(int x,int y,int k) 54 { 55 int l=1,r=n,xx=rt[x-1],yy=rt[y]; 56 if(s[yy]-s[xx]<k)return -1; 57 while(l!=r) 58 { 59 int mid=(l+r)>>1; 60 if(s[ls[yy]]-s[ls[xx]]>=k){xx=ls[xx];yy=ls[yy];r=mid;} 61 else {k-=s[ls[yy]]-s[ls[xx]];xx=rs[xx];yy=rs[yy];l=mid+1;} 62 } 63 return l; 64 } 65 int main() 66 { 67 freopen("input.txt","r",stdin); 68 freopen("output.txt","w",stdout); 69 n=read(); 70 for1(i,n) 71 { 72 memset(st,0,sizeof(st)); 73 scanf("%s",st+1);m=strlen(st+1); 74 now=1; 75 for3(j,m,1) 76 { 77 int x=st[j]-'a'; 78 if(!t[now][x])t[now][x]=++cnt; 79 now=t[now][x]; 80 } 81 p[i]=now;G[now].push_back(i); 82 } 83 now=0; 84 dfs(1); 85 for1(i,n) 86 { 87 int k=read(); 88 printf("%d\n",query(dfn[p[i]][0],dfn[p[i]][1],k)); 89 } 90 return 0; 91 }