zoukankan      html  css  js  c++  java
  • [bzoj2754] [SCOI2012]喵星球上的点名

    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 
    

    Sample Output

    2 
    1 
    0 
    1 2 
    

    Solution

    先建出后缀数组,求一发(height)

    然后正解是按字典序用树状数组维护颜色,然后随便搞搞。。

    其实这题直接暴力是可以过官方数据的。

    暴力向上和向下跳,枚举颜色更新答案就行。

    #include<bits/stdc++.h>
    using namespace std;
     
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
     
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    const int maxn = 5e5+10;
    
    int N,M,n,s[maxn],col[maxn],st[maxn],len[maxn];
    
    int spx[maxn],spy[maxn],sa[maxn],rk[maxn],height[maxn],sum[maxn];
    
    void get_sa() {
    	int p=0,m=n+10000,*x=spx,*y=spy;
    	for(int i=1;i<=n;i++) sum[x[i]=s[i]]++;
    	for(int i=1;i<=m;i++) sum[i]+=sum[i-1];
    	for(int i=n;i;i--) sa[sum[x[i]]--]=i;
    
    	for(int k=1,tot=0;p<n;tot=0,k<<=1) {
    		p=0;
    		for(int i=n-k+1;i<=n;i++) y[++tot]=i;
    		for(int i=1;i<=n;i++) if(sa[i]>k) y[++tot]=sa[i]-k;
    
    		for(int i=1;i<=m;i++) sum[i]=0;
    		for(int i=1;i<=n;i++) sum[x[y[i]]]++;
    		for(int i=1;i<=m;i++) sum[i]+=sum[i-1];
    		for(int i=n;i;i--) sa[sum[x[y[i]]]--]=y[i];
    
    		swap(x,y),x[sa[1]]=p=1;
    		for(int i=2;i<=n;i++)
    			if(y[sa[i]]!=y[sa[i-1]]||y[sa[i]+k]!=y[sa[i-1]+k]) x[sa[i]]=++p;
    			else x[sa[i]]=p;
    		m=p;
    	}
    }
    
    void get_height() {
    	for(int i=1;i<=n;i++) rk[sa[i]]=i;
    	int p=0;
    	for(int i=1;i<=n;i++) {
    		if(p) p--;
    		while(s[i+p]==s[sa[rk[i]-1]+p]) p++;
    		height[rk[i]]=p;
    	}
    }
    
    int t[maxn],res[maxn];
    
    int main() {
    	read(N),read(M);
    	for(int i=1;i<=N;i++) {
    		int k,x;read(k);
    		while(k--) read(x),s[++n]=x,col[n]=i;
    		read(k);s[++n]=10000+i+N+M;
    		while(k--) read(x),s[++n]=x,col[n]=i;
    		s[++n]=10000+i;
    	}
    	for(int i=1;i<=M;i++) {
    		int k,x;read(k);len[i]=k,st[i]=n+1;
    		while(k--) read(x),s[++n]=x,col[n]=N+i;
    		s[++n]=10000+N+i;
    	}
    	get_sa(),get_height();
    	for(int i=1;i<=M;i++) {
    		int pos=rk[st[i]],p1,p2;
    		for(p1=pos;p1>1;p1--) if(height[p1]<len[i]) break;
    		for(p2=pos+1;p2<=n;p2++) if(height[p2]<len[i]) break;p2--;
    		int ans=0;
    		for(int p=p1;p<=p2;p++) {
    			int c=col[sa[p]];
    			if(c>N) continue;
    			if(t[c]!=i) t[c]=i,ans++,res[c]++;
    		}
    		write(ans);
    	}
    	for(int i=1;i<=N;i++) printf("%d ",res[i]);puts("");
    	return 0;
    }
    
  • 相关阅读:
    【引用】关于closeonexec标志
    CentOS解决编码问题
    /etc/init.d/functions (转)
    centos 安装 中文 支持 语言包(转)
    vsftpd 530 错误
    __FILE__,__LINE__,FUNCTION__实现代码跟踪调试(linux下c语言编程)(转)
    C语言中可变参数的用法 va_start va_end(转)
    守护进程 setsid(转)
    /dev/null 重定向 ./sh >/dev/null 2>&1
    C# 子类调用父类构造函数
  • 原文地址:https://www.cnblogs.com/hbyer/p/10286989.html
Copyright © 2011-2022 走看看