题目

  

2754: [SCOI2012]喵星球上的点名

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 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

 

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;  
}  

 

 

posted on 2017-05-08 16:08  void_zxh  阅读(244)  评论(0编辑  收藏  举报