题目
2754: [SCOI2012]喵星球上的点名
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 2261 Solved: 979
[Submit][Status][Discuss]
Description
a180285幸运地被选做了地球到喵星球的留学生。他发现喵星人在上课前的点名现象非常有趣。 假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成。喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这个喵星人就必须答到。 然而,由于喵星人的字码过于古怪,以至于不能用ASCII码来表示。为了方便描述,a180285决定用数串来表示喵星人的名字。
现在你能帮助a180285统计每次点名的时候有多少喵星人答到,以及M次点名结束后每个喵星人答到多少次吗?
Input
现在定义喵星球上的字符串给定方法:
先给出一个正整数L,表示字符串的长度,接下来L个整数表示字符串的每个字符。
输入的第一行是两个整数N和M。
接下来有N行,每行包含第i 个喵星人的姓和名两个串。姓和名都是标准的喵星球上的
字符串。
接下来有M行,每行包含一个喵星球上的字符串,表示老师点名的串。
Output
对于每个老师点名的串输出有多少个喵星人应该答到。
然后在最后一行输出每个喵星人被点到多少次。
Sample Input
2 3
6 8 25 0 24 14 8 6 18 0 10 20 24 0
7 14 17 8 7 0 17 0 5 8 25 0 24 0
4 8 25 0 24
4 7 0 17 0
4 17 0 8 25
6 8 25 0 24 14 8 6 18 0 10 20 24 0
7 14 17 8 7 0 17 0 5 8 25 0 24 0
4 8 25 0 24
4 7 0 17 0
4 17 0 8 25
Sample Output
2
1
0
1 2
【提示】
事实上样例给出的数据如果翻译成地球上的语言可以这样来看
2 3
izayoi sakuya
orihara izaya
izay
hara
raiz
HINT
【数据范围】
对于30%的数据,保证:
1<=N,M<=1000,喵星人的名字总长不超过4000,点名串的总长不超过2000。
对于100%的数据,保证:
1<=N<=20000,1<=M<=50000,喵星人的名字总长和点名串的总长分别不超过100000,保证喵星人的字符串中作为字符存在的数不超过10000。
题解
首先,我们发现,这道题啊,时间限制为20s~(~ ̄▽ ̄)~
SO 直接暴力(瞎扯(*  ̄︿ ̄))。。。
我们应该用后缀数组来进行暴力
First 我们先将全部的姓名串和点名串连接起来,并记录每个点名串在总串中的起始位置和长度。
Second 求出height,sa,rank。
Last 枚举每个点名串
由rank[该点名串的起始位置]在height[]向前x向后拓展
遇到height[i]<点名串长度,就停止拓展。(唯一的跳出循环的标志)
然后在这拓展出来的一排位置中找出有多少是属于姓名串的,记录即可。
(PS:亦可以一边拓展,一边判定属于哪个姓名串)
附上我的程序,Time:10104 ms
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <algorithm> using namespace std; int s[500000+10000]; int rank[500000+10000],wb[500000+10000],wv[500000+10000],wss[500000+10000]; int r[500000+10000],sa[500000+10000]; int height[500000+10000]; int id[500010],cou[500010]; //bool same1[500010]; //int deta[500010]; struct li { int le,ni,sti; }ll[500010]; bool cmp(int *r,int a,int b,int l) { return r[a]==r[b] && r[a+l]==r[b+l]; } void da(int n,int m) { int i,j,p,*x=rank,*y=wb,*t; for(i=0;i<m;i++) wss[i]=0; for(i=0;i<n;i++) wss[x[i]=r[i]]++; for(i=1;i<m;i++) wss[i]+=wss[i-1]; for(i=n-1;i>=0;i--) sa[--wss[x[i]]]=i; for(j=1,p=1;p<n;j*=2,m=p) { for(p=0,i=n-j;i<n;i++) y[p++]=i; for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j; for(i=0;i<n;i++) wv[i]=x[y[i]]; for(i=0;i<m;i++) wss[i]=0; for(i=0;i<n;i++) wss[wv[i]]++; for(i=1;i<m;i++) wss[i]+=wss[i-1]; for(i=n-1;i>=0;i--) sa[--wss[wv[i]]]=y[i]; for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; } } void calheight(int n) { int i,j,k=0; for(i=1;i<=n;i++) rank[sa[i]]=i; for(i=0;i<n;height[rank[i++]]=k) for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++); return; } inline void write(int re) { /* if (re<0) { putchar('-'); re=-re; } */ if (re>9) write(re/10); putchar(re%10+'0'); } bool ci[500010]; bool cmp1(li aii,li bii) { if(aii.le==bii.le) return aii.ni<bii.ni; return aii.le<bii.le; } int laji1()//没用 { /*int solve1(int k,int u,int l,int m1,int m2)//没用 { int i,j,ans=0; bool on1=0,on2=0; for(i=1;i<=m2;i++) deta[i]=cou[i]; for(i=0;i<=m1+m2;i++) ci[i]=0; for(i=m1*2+m2;i<=l;i++) { if(id[sa[i-1]]==u&&id[sa[i-1]+k-1]==u) on1=1; if(id[sa[i+1]]==u&&id[sa[i+1]+k-1]==u) on2=1; if(height[i]>=k&&on1==1) { if(id[sa[i]]!=0&&id[sa[i]]<=m1&&ci[id[sa[i]]]==0) { cou[id[sa[i]]]++; ci[id[sa[i]]]=1; ans++; } if(id[sa[i-1]]!=0&&id[sa[i-1]]<=m1&&ci[id[sa[i-1]]]==0) { cou[id[sa[i-1]]]++; ci[id[sa[i]]]=1; ans++; } } else on1=0; if(height[i+1]>=k&&on2==1) { if(id[sa[i]]!=0&&id[sa[i]]<=m1&&ci[id[sa[i]]]==0) { cou[id[sa[i]]]++; ci[id[sa[i]]]=1; ans++; } if(id[sa[i+1]]!=0&&id[sa[i+1]]<=m1&&ci[id[sa[i+1]]]==0) { cou[id[sa[i-1]]]++; ci[id[sa[i]]]=1; ans++; } } else on2=0; } on1=0; on2=0; for(i=l;i>=m1*2+m2;i--) { if(id[sa[i-1]]==u&&id[sa[i-1]+k-1]==u) on1=1; if(id[sa[i+1]]==u&&id[sa[i+1]+k-1]==u) on2=1; if(height[i]>=k&&on1==1) { if(id[sa[i]]!=0&&id[sa[i]]<=m1&&ci[id[sa[i]]]==0) { cou[id[sa[i]]]++; ci[id[sa[i]]]=1; ans++; } if(id[sa[i-1]]!=0&&id[sa[i-1]]<=m1&&ci[id[sa[i-1]]]==0) { cou[id[sa[i-1]]]++; ci[id[sa[i]]]=1; ans++; } } else on1=0; if(height[i+1]>=k&&on2==1) { if(id[sa[i]]!=0&&id[sa[i]]<=m1&&ci[id[sa[i]]]==0) { cou[id[sa[i]]]++; ci[id[sa[i]]]=1; ans++; } if(id[sa[i+1]]!=0&&id[sa[i+1]]<=m1&&ci[id[sa[i+1]]]==0) { cou[id[sa[i-1]]]++; ci[id[sa[i]]]=1; ans++; } } else on2=0; } for(i=1;i<=m2;i++) deta[i]=cou[i]-deta[i]; return ans; }*/ } int solve(int k,int l,int m1,int m2,int wi) { int i,j,ans=0; //for(i=1;i<=m2;i++) //deta[i]=cou[i]; for(i=0;i<=m1+m2;i++) ci[i]=0; //if(wi<0||wi>l) // return 0; int wz=rank[wi]; for(i=wz+1;i<=l;i++) { if(height[i]>=k) { if(id[sa[i]]<=m1&&id[sa[i]]!=0&&ci[id[sa[i]]]==0) { ci[id[sa[i]]]=1; cou[id[sa[i]]]++; ans++; } } else break; } for(i=wz;i>m1*2+m2;i--) { if(height[i]>=k) { if(id[sa[i-1]]<=m1&&id[sa[i-1]]!=0&&ci[id[sa[i-1]]]==0) { ci[id[sa[i-1]]]=1; cou[id[sa[i-1]]]++; ans++; } } else break; } //for(i=1;i<=m2;i++) // deta[i]=cou[i]-deta[i]; return ans; } int laji2()//没用 { /*void get_same(int ui)//没用 { int i,j; bool p=0; for(i=ll[ui].sti,j=ll[ui-1].sti;i<=ll[ui].sti+ll[ui].le-1;i++,j++) if(s[i]!=s[j]) { p=1; break; } if(p==0) same1[ui]=1; else same1[ui]=0; }*/ } int main() { //freopen("test.txt","r",stdin); //freopen("a.out","w",stdout); int l=0,m1,m2,i,j,len1; scanf("%d %d",&m1,&m2); l=0; for(i=1;i<=m1;i++) { scanf("%d",&len1); for(j=0;j<len1;j++) { scanf("%d",&s[l]); s[l]+=2; id[l++]=i; } s[l]=1,id[l++]=0; scanf("%d",&len1); for(j=0;j<len1;j++) { scanf("%d",&s[l]); s[l]+=2; id[l++]=i; } s[l]=1,id[l++]=0; } for(i=1;i<=m2;i++) { scanf("%d",&len1); ll[i].le=len1; ll[i].ni=m1+i; ll[i].sti=l; for(j=0;j<len1;j++) { scanf("%d",&s[l]); s[l]+=2; id[l++]=m1+i; } if(i!=m2) s[l]=1,id[l++]=0; } for(i=0;i<l;i++) r[i]=s[i]; r[l]=0; da(l+1,10100); calheight(l); { /*printf("%s\n",s); for(i=0;i<l;i++) printf("%d ",id[i]); printf("\n");*/ /*for(int i=1;i<=l;i++) write(sa[i]+1),putchar(' '); puts(""); for(int i=1;i<=l;i++) { write(height[i]); putchar(' '); } puts("");*/ /*for(i=1;i<=l;i++) { printf("%d %d ",height[i],id[sa[i]]); for(int j=sa[i];j<=l;j++) cout<<char(95+s[j]); cout<<endl; }*/ /*int lii=0,rii=las,mid; while(lii<=rii) { mid=(lii+rii)>>1; if(judge(mid,l,m)) lii=mid+1; else rii=mid-1; } printf("%d\n",lii-1);*/ } //int ans1[100010]; /*sort(ll+1,ll+m2+1,cmp1); for(i=2;i<=m2;i++) if(ll[i].le==ll[i-1].le) get_same(i);*/ for(i=1;i<=m2;i++) { //if(same1[i]==0) //ans1[i]=solve(ll[i].le,l,m1,m2,ll[i].sti); /*else { ans1[ll[i].ni]=ans1[ll[i-1].ni]; for(j=1;j<=m2;j++) cou[j]+=deta[j]; }*/ printf("%d\n",solve(ll[i].le,l,m1,m2,ll[i].sti)); } //for(i=m1+1;i<=m1+m2;i++) //printf("%d\n",ans1[i]); for(j=1;j<m1;j++) printf("%d ",cou[j]); printf("%d\n",cou[m1]); return 0; }
额貌似有点慢
再附上一个厉害的代码,同样的方法,Time:1708 ms
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 501000 #define M 50100 #define inf 10100 using namespace std; int s[N],len; int sa[N],rank[N],height[N]; int cnt[N],val[N],_val[N]; int stk[N],top; int n,m,crs[N]; struct QUERY { int n,s; }Query[M]; int ans[M],vis[M]; void Input() { int i,j,k,fengefu=inf; scanf("%d%d",&n,&m); // 为了避免多匹配,所以分隔符都不一样 for(i=1;i<=n;i++) // 读入每个喵的姓名,中间有分隔符。 { for(scanf("%d",&k);k--;) { crs[len]=i; scanf("%d",&s[len++]); } s[len++]=++fengefu; for(scanf("%d",&k);k--;) { crs[len]=i; scanf("%d",&s[len++]); } s[len++]=++fengefu; } for(i=1;i<=m;i++) // 输入每个点名 { scanf("%d",&Query[i].n); Query[i].s=len; for(j=1;j<=Query[i].n;j++) scanf("%d",&s[len++]); s[len++]=++fengefu; } } inline bool cmp(int x,int y,int hl) {return val[x]==val[y]&&((x+hl>=len&&y+hl>=len)||(x+hl<len&&y+hl<len&&val[x+hl]==val[y+hl]));} void SA(int lim=256) { int i,j,k,hl; for(i=0;i<lim;i++)cnt[i]=0; for(i=0;i<len;i++)cnt[val[i]=s[i]]++; for(i=1;i<lim;i++)cnt[i]+=cnt[i-1]; for(i=len-1;i>=0;i--)sa[--cnt[val[i]]]=i; for(k=0;;k++) { top=0,hl=1<<k; for(i=0;i<len;i++)if(sa[i]+hl>=len)stk[++top]=sa[i]; for(i=0;i<len;i++)if(sa[i]>=hl)stk[++top]=sa[i]-hl; for(i=0;i<lim;i++)cnt[i]=0; for(i=0;i<len;i++)cnt[val[i]]++; for(i=1;i<lim;i++)cnt[i]+=cnt[i-1]; for(i=len;i;i--)sa[--cnt[val[stk[i]]]]=stk[i]; for(i=lim=0;i<len;lim++) { for(j=i;j<len-1&&cmp(sa[j],sa[j+1],hl);j++); for(;i<=j;i++)_val[sa[i]]=lim; } for(i=0;i<len;i++)val[i]=_val[i]; if(lim==len)break; } for(i=0;i<len;i++)rank[sa[i]]=i; for(k=i=0;i<len;i++) { if(k)k--; if(!rank[i])continue; while(s[i+k]==s[sa[rank[i]-1]+k])k++; height[rank[i]]=k; } } void Work() { int i,j,k; int l,r,res; for(i=1;i<=m;i++){ l=r=rank[Query[i].s]; while(height[l]>=Query[i].n)l--; while(height[r]>=Query[i].n)r++; r--,res=0; for(j=l;j<=r;j++){ if(crs[sa[j]]){ if(vis[crs[sa[j]]]!=i){ vis[crs[sa[j]]]=i; res++; ans[crs[sa[j]]]++; } } } printf("%d\n",res); } for(i=1;i<=n;i++) { printf("%d",ans[i]); if(i!=n)putchar(' '); } } int main() { //freopen("test.txt","r",stdin); //freopen("std2.out","w",stdout); Input(); SA(200000); Work(); return 0; }