BZOJ 2754([SCOI2012]喵喵叫的星球-统计序列的后缀阵列中子序列出现次数)
2754: [SCOI2012]喵喵叫的星球
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 805 Solved: 380
[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。
Source
这题是后缀数组。
先把模式串P写成s11*s12*s21*s22...sn2 (*为特殊字符)
然后用find统计sa中出现上下界 平均O(Len总logLen总+MlogLen总) 最坏O(MLen总)
可能会T但正解至今仍不知道
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<functional> #include<iostream> #include<cmath> #include<cctype> #include<ctime> using namespace std; #define For(i,n) for(int i=1;i<=n;i++) #define Fork(i,k,n) for(int i=k;i<=n;i++) #define Rep(i,n) for(int i=0;i<n;i++) #define ForD(i,n) for(int i=n;i;i--) #define RepD(i,n) for(int i=n;i>=0;i--) #define Forp(x) for(int p=pre[x];p;p=next[p]) #define Forpiter(x) for(int &p=iter[x];p;p=next[p]) #define Lson (x<<1) #define Rson ((x<<1)+1) #define MEM(a) memset(a,0,sizeof(a)); #define MEMI(a) memset(a,127,sizeof(a)); #define MEMi(a) memset(a,128,sizeof(a)); #define INF (2139062143) #define F (100000007) #define MAXN (1000000+10) #define Sigma_size (10000+10) #define sp_char (10001) typedef long long ll; ll mul(ll a,ll b){return (a*b)%F;} ll add(ll a,ll b){return (a+b)%F;} ll sub(ll a,ll b){return (a-b+(a-b)/F*F+F)%F;} void upd(ll &a,ll b){a=(a%F+b%F)%F;} // 约定 -1:/0 sp_char:* cat[i]=0 该位置无猫 class SA { public: int s[MAXN]; int sa[MAXN],t[MAXN],t2[MAXN],c[MAXN],n; SA(){} SA(int *_s,int _n){memcpy(s,_s,sizeof(s));n=_n;MEM(sa) MEM(t) MEM(t2) MEM(c) } void mem(int *_s,int _n){memcpy(s,_s,sizeof(s));n=_n;MEM(sa) MEM(t) MEM(t2) MEM(c) } void build_sa(int m) { int *x=t,*y=t2; Rep(i,m) c[i]=0; Rep(i,n) c[x[i]=s[i]]++; //x[i] 第i个字符串第一keyword排第几 For(i,m-1) c[i]+=c[i-1]; RepD(i,n-1) sa[--c[x[i]]]=i; for(int k=1;k<=n;k<<=1) { int p=0; Fork(i,n-k,n-1) y[p++]=i; Rep(i,n) if (sa[i]>=k) y[p++]=sa[i]-k; //y[i] 第二keyword排i的是第?字符串 Rep(i,m) c[i]=0; Rep(i,n) c[x[y[i]]]++; // x[y[i]] 第二keyword排i的字符串,第1keyword排第几 For(i,m-1) c[i]+=c[i-1]; RepD(i,n-1) sa[--c[x[y[i]]]]=y[i]; //第二keyword从大到小遍历。以第一keyword排序 ,最后得到以1,2keyword排序的 //此时sa为第一keyword。第2keyword均排好序的 swap(x,y); //此时y变为第一keyword排序的rank,目标是把x变成第一,二keyword排序的rank p=1; x[sa[0]]=0; For(i,n-1) x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i]+k]==y[sa[i-1]+k] ? p-1:p++; if (p>=n) break; m=p; } } int m; //模板串P的长度要事先赋值 int cmp_suffix(int *pattern,int p) { for(int i=0;i<m;i++) { if (pattern[i]!=s[sa[p]+i]) return pattern[i]-s[sa[p]+i]; } return 0; } int find(int *P,int _m) { m=_m; //这里赋值也行 if (cmp_suffix(P,0)<0||cmp_suffix(P,n-1)>0) return -1; int L=0,R=n-1; while(L<=R) { int M=(L+R)>>1; int res=cmp_suffix(P,M); if (!res) return M; else if (res<0) R=M-1; else L=M+1; } return -1; } int rank[MAXN],height[MAXN]; void make_height() { int k=0; Rep(i,n) rank[sa[i]]=i; Rep(i,n) { if (rank[i]-1<0) continue; if (k) k--; int j=sa[rank[i]-1]; while(s[i+k]==s[j+k]) ++k; height[rank[i]]=k; } } }S; int flag[MAXN]={0},cat[MAXN]={0},sum[MAXN]={0}; int len,s[MAXN]; int n,m; int get_init(int &p,int i,bool is_cat) { int len; scanf("%d",&len); while(len--) { scanf("%d",&s[++p]); if (is_cat) cat[p]=i; } return len; } int main() { // freopen("bzoj2754.in","r",stdin); // freopen(".out","w",stdout); scanf("%d%d",&n,&m); int p=-1; For(i,n) { For(j,2) { get_init(p,i,1); s[++p]=sp_char;cat[p]=0; } } s[++p]=-1; S.mem(s,p); S.build_sa(Sigma_size); S.make_height(); For(i,m) { p=-1; get_init(p,i,0); s[++p]=-1; int K=S.find(s,p); if (K==-1) { cout<<"0\n"; continue; } int ans=0; int t=S.sa[K]; if (flag[cat[t]]^i) sum[cat[t]]++,flag[cat[t]]=i,++ans; int k=K; while (k>0&&S.cmp_suffix(s,k-1)==0) { k--; int t=S.sa[k]; if (flag[cat[t]]^i) sum[cat[t]]++,flag[cat[t]]=i,++ans; } k=K; while (k<S.n&&S.cmp_suffix(s,k+1)==0) { k++; int t=S.sa[k]; if (flag[cat[t]]^i) sum[cat[t]]++,flag[cat[t]]=i,++ans; } printf("%d\n",ans); } printf("%d",sum[1]); Fork(i,2,n) printf(" %d",sum[i]); putchar('\n'); return 0; }
版权声明:本文博主原创文章。博客,未经同意不得转载。