bzoj 2754: [SCOI2012]喵星球上的点名
2017-07-06 20:23
337 查看
Description
a180285幸运地被选做了地球到喵星球的留学生。他发现喵星人在上课前的点名现象非常有趣。 假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成。喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这个喵星人就必须答到。 然而,由于喵星人的字码过于古怪,以至于不能用ASCII码来表示。为了方便描述,a180285决定用数串来表示喵星人的名字。现在你能帮助a180285统计每次点名的时候有多少喵星人答到,以及M次点名结束后每个喵星人答到多少次吗?
Input
现在定义喵星球上的字符串给定方法:先给出一个正整数L,表示字符串的长度,接下来L个整数表示字符串的每个字符。
输入的第一行是两个整数N和M。
接下来有N行,每行包含第i 个喵星人的姓和名两个串。姓和名都是标准的喵星球上的
字符串。
接下来有M行,每行包含一个喵星球上的字符串,表示老师点名的串。
Output
对于每个老师点名的串输出有多少个喵星人应该答到。然后在最后一行输出每个喵星人被点到多少次。
Sample Input
2 36 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
21
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
这个题是叉姐考试的一道AC自动机题,当场这题有n种做法都可以AC这题我是看了洛谷标签上有莫队才做的。。。
首先还是要拼成一个串(把询问串也拼起来),然后记录每个后缀的开头属于哪个串,对于询问串还要记下串的开头在串中的位置st[i];
对于询问的话,如果询问串是别的串的子串的话,那么以询问串的开头为开头的后缀与以别的串的字母开头的后缀的lcp>=该串长度;
因为靠的越近lcp越大,所以我们只需要从rank[st[i]],向前后扩展直到height<le[i]为止,那么中间的l--r的后缀就是满足条件的后缀,具体实现和TJOI 单词一样
第一问相当于询问l--r中有多少个不同的数,是莫队的基础套路题,开个桶即可;
第二问相当于l--r的区间加法,因为不能重复加,所以一开始是想线段树直接区间加法,但一个串每个询问只加一次不好保证。
其实这个东西可以直接在莫队的过程中实现:
每新出现一个数,就默认它在后面的询问区间都出现,即加上(m-i+1);
每有一个数消失,就默认它在后面的询问区间都不出现,然后把原来多加的减去,即减去(m-i+1);
几个傻逼错误:1.block=sqrt(len)写成=sqrt(n)了;
2.从rank[st[i]]扩展的时候,左边可能扩展到0,右边如果是while(height[r]>=le[i]) r++;最后的r是不满足条件的,要最后r--;
代码能力真的越来越不行了。。。
(upd:我真的是石乐志。。。都while暴跳左右两边了,就是裸暴力的复杂度了,我就说我的莫队怎么跑得这么慢,跟个暴力似的QAQ。。找l和r的话二分长度即可logn找完。。。)
// MADE BY QT666 #include<cstdio> #include<algorithm> #include<cmath> #include<iostream> #include<cstring> #define RG register using namespace std; typedef long long ll; const int N=1000050; const int Inf=19260817; int gi(){ int x=0,flag=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();} while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x*flag; } int sa ,y ,rk,rnk ,height ,bl ,len,a ,n,m,st ,le ,cnt ,ans ,ans2 ,pos ,block; struct data{ int fir,sec,id; }x ; struct ac{ int l,r,id; }q ; bool cmp(const data &a,const data &b){ if(a.fir==b.fir) return a.sec<b.sec; else return a.fir<b.fir; } void work2(){ rk=1;y[x[1].id]=rk; for(RG int i=2;i<=len;i++){ if(x[i-1].fir!=x[i].fir||x[i-1].sec!=x[i].sec) rk++; y[x[i].id]=rk; } } void work(){ sort(x+1,x+1+len,cmp);work2(); for(RG int i=1;i<=len;i<<=1){ for(RG int j=1;j+i<=len;j++) x[j].fir=y[j],x[j].sec=y[j+i],x[j].id=j; for(RG int j=len-i+1;j<=len;j++) x[j].fir=y[j],x[j].sec=0,x[j].id=j; sort(x+1,x+1+len,cmp);work2(); if(rk==len) break; } } void get_height(){ int kk=0;for(RG int i=1;i<=len;i++) rnk[sa[i]]=i; for(RG int i=1;i<=len;i++){ if(kk) kk--; int j=sa[rnk[i]-1]; while(a[i+kk]==a[j+kk]) kk++; height[rnk[i]]=kk; } } bool cmp2(ac a,ac b){ if(pos[a.l]==pos[b.l]) return a.r<b.r; return pos[a.l]<pos[b.l]; } void Modui(){ int num=0; for(RG int i=1,l=1,r=0;i<=m;i++){ while(l>q[i].l) {l--,cnt[bl[sa[l]]]++;if(cnt[bl[sa[l]]]==1&&bl[sa[l]]<=n&&bl[sa[l]]) num++,ans2[bl[sa[l]]]+=(m-i+1);} while(r<q[i].r) {r++,cnt[bl[sa[r]]]++;if(cnt[bl[sa[r]]]==1&&bl[sa[r]]<=n&&bl[sa[r]]) num++,ans2[bl[sa[r]]]+=(m-i+1);} while(l<q[i].l) {cnt[bl[sa[l]]]--;if(!cnt[bl[sa[l]]]&&bl[sa[l]]<=n&&bl[sa[l]]) num--,ans2[bl[sa[l]]]-=(m-i+1);l++;} while(r>q[i].r) {cnt[bl[sa[r]]]--;if(!cnt[bl[sa[r]]]&&bl[sa[r]]<=n&&bl[sa[r]]) num--,ans2[bl[sa[r]]]-=(m-i+1);r--;} ans[q[i].id]=num; } } int main(){ n=gi(),m=gi(); for(RG int i=1;i<=n;i++){ int l=gi(); for(int j=1;j<=l;j++) a[++len]=gi(),bl[len]=i; int l2=gi(); a[++len]=Inf+i;bl[len]=N-1; for(int j=1;j<=l2;j++) a[++len]=gi(),bl[len]=i; a[++len]=Inf;bl[len]=N-1; } for(RG int i=1;i<=m;i++){ int l=gi();st[i]=len+1;le[i]=l; for(int j=1;j<=l;j++) a[++len]=gi(),bl[len]=n+i; a[++len]=Inf;bl[len]=N-1; } for(RG int i=1;i<=len;i++){ x[i].id=i;x[i].fir=x[i].sec=a[i]; } work();for(int i=1;i<=len;i++) sa[y[i]]=i; get_height(); for(RG int i=1;i<=m;i++){ int g=rnk[st[i]],l=g,r=g; while(height[l]>=le[i]) l--; while(height[r+1]>=le[i]) r++; q[i].l=l,q[i].r=r;q[i].id=i; } block=(int)sqrt(len); for(RG int i=1;i<=len;i++) pos[i]=(i-1)/block+1; sort(q+1,q+1+m,cmp2);Modui(); for(RG int i=1;i<=m;i++) printf("%d\n",ans[i]); for(RG int i=1;i<n;i++) printf("%d ",ans2[i]); printf("%d",ans2 ); return 0; }
相关文章推荐
- bzoj2754:[SCOI2012]喵星球上的点名(后缀自动机)
- BZOJ 2754 SCOI2012 喵星球上的点名 fail树+set启发式合并
- BZOJ 2754: [SCOI2012]喵星球上的点名 [后缀数组+暴力]
- BZOJ 2754: [SCOI2012]喵星球上的点名
- bzoj2754 [SCOI2012]喵星球上的点名
- bzoj 2754: [SCOI2012]喵星球上的点名【AC自动机】
- BZOJ 2754([SCOI2012]喵星球上的点名-后缀数组统计序列集合中子序列出现次数)
- [bzoj2754] [SCOI2012]喵星球上的点名
- 【bzoj2754】[SCOI2012]喵星球上的点名 AC自动机优化的暴力
- BZOJ_2754__[SCOI2012]_喵星球上的点名_(暴力+后缀数组)
- bzoj 2754: [SCOI2012]喵星球上的点名
- BZOJ 2754: [SCOI2012]喵星球上的点名
- BZOJ 2754 [SCOI2012]喵星球上的点名
- BZOJ2754 SCOI2012喵星球上的点名
- BZOJ 2754: [SCOI2012]喵星球上的点名 后缀数组
- BZOJ 2754: [SCOI2012]喵星球上的点名
- bzoj2754 [SCOI2012]喵星球上的点名(后缀数组+暴力)
- BZOJ 2754: [SCOI2012]喵星球上的点名
- AC日记——[SCOI2012]喵星球上的点名 bzoj 2754
- BZOJ 2754: [SCOI2012]喵星球上的点名 [AC自动机+map+暴力]