zoukankan      html  css  js  c++  java
  • BZOJ 4698: Sdoi2008 Sandy的卡片

    4698: Sdoi2008 Sandy的卡片

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 225  Solved: 95
    [Submit][Status][Discuss]

    Description

    Sandy和Sue的热衷于收集干脆面中的卡片。然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积
    攒卡片兑换超炫的人物模型。每一张卡片都由一些数字进行标记,第i张卡片的序列长度为Mi,要想兑换人物模型
    ,首先必须要集够N张卡片,对于这N张卡片,如果他们都有一个相同的子串长度为k,则可以兑换一个等级为k的人
    物模型。相同的定义为:两个子串长度相同且一个串的全部元素加上一个数就会变成另一个串。Sandy的卡片数远
    远小于要求的N,于是Sue决定在Sandy的生日将自己的卡片送给Sandy,在Sue的帮助下,Sandy终于集够了N张卡片
    ,但是,Sandy并不清楚他可以兑换到哪个等级的人物模型,现在,请你帮助Sandy和Sue,看看他们最高能够得到
    哪个等级的人物模型。

    Input

    第一行为一个数N,表示可以兑换人物模型最少需要的卡片数,即Sandy现在有的卡片数
    第i+1行到第i+N行每行第一个数为第i张卡片序列的长度Mi,之后j+1到j+1+Mi个数,用空格分隔,分别表示序列中
    的第j个数
    n<=1000,M<=1000,2<=Mi<=101

    Output

    一个数k,表示可以获得的最高等级。

    Sample Input

    2
    2 1 2
    3 4 5 9

    Sample Output

    2

    HINT

    Source

    分析:

    深夜写模板题...听起来不错...

    把$n$个串连起来求一个后缀数组,然后二分答案$k$,判断是否存在一个连续的$height>=k$区间出现了$n$个串...

    代码:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    //by NeighThorn
    using namespace std;
    
    const int maxn=1000+5,maxm=1000+5,maxlen=2000000+5;
    
    int n,m,Min,s[maxlen],id[maxlen],len[maxn],vis[maxn],str[maxn][maxm];
    int sa[maxlen],gs[maxlen],wb[maxlen],wv[maxlen],ran[maxlen],height[maxlen];
    
    inline bool cmp(int *x,int a,int b,int l){
    	return x[a]==x[b]&&x[a+l]==x[b+l];
    }
    
    inline void da(int *sa,int *x,int n,int m){
    	int i,j,p,*y=wb;
    	for(i=0;i<m;i++) gs[i]=0;
    	for(i=0;i<n;i++) gs[x[i]]++;
    	for(i=1;i<m;i++) gs[i]+=gs[i-1];
    	for(i=n-1;~i;i--) sa[--gs[x[i]]]=i;
    	for(j=1,p=1;p<n;j<<=1,m=p){
    		for(i=n-j,p=0;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++) gs[i]=0;
    		for(i=0;i<n;i++) gs[wv[i]]++;
    		for(i=1;i<m;i++) gs[i]+=gs[i-1];
    		for(i=n-1;~i;i--) sa[--gs[wv[i]]]=y[i];
    		p=1;swap(x,y);x[sa[0]]=0;
    		for(i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;
    	}
    }
    
    inline void calcheight(int n){
    	int i,j,k=0;
    	for(i=0;i<=n;i++) ran[sa[i]]=i;
    	for(i=0;i<n;height[ran[i++]]=k)
    		for(k?k--:233,j=sa[ran[i]-1];s[j+k]==s[i+k];k++);
    }
    
    inline bool check(int k){
    	int cnt=0;
    	for(int l=1,r;l<=n;l=r+1){
    		while(l<n&&height[l]<k) l++;
    		r=l;if(r==n&&height[r]<k) return false;
    		while(r<n&&height[r+1]>=k) r++;
    		if(r-l+2>=m){
    			memset(vis,0,sizeof(vis));cnt=0;
    			for(int i=l-1;i<=r;i++)
    				if(id[sa[i]]) cnt+=vis[id[sa[i]]]^1,vis[id[sa[i]]]=1;	
    			if(cnt==m) return true;
    		}
    	}
    	return false;
    }
    
    signed main(void){
    #ifndef ONLINE_JUDGE
    	freopen("in.txt","r",stdin);
    #endif
    	scanf("%d",&m);Min=1000;
    	for(int i=1;i<=m;i++){
    		scanf("%d",&len[i]),Min=min(Min,len[i]);
    		for(int j=1;j<=len[i];j++)
    			scanf("%d",&str[i][j]);
    	}
    	n=0;
    	for(int i=1;i<=m;i++,ran[n]=s[n++]=2000+i)
    		for(int j=2;j<=len[i];j++)
    			id[n]=i,ran[n]=s[n++]=str[i][j]-str[i][j-1];
    	da(sa,ran,n+1,4000);calcheight(n);
    	int l=1,r=Min-1,ans=0;
    	while(l<=r){
    		int mid=(l+r)>>1;
    		if(check(mid)) ans=mid,l=mid+1;
    		else r=mid-1;
    	}
    	printf("%d
    ",ans+1);
    	return 0;
    }
    

      


    By NeighThorn

     
  • 相关阅读:
    CSS文本部分之字体样式[1]
    CSS基础之简单介绍
    [09]HTML基础之全局属性
    [08]HTML基础之视频标签
    [07]HTML基础之图片标签
    [06]HTML基础之表单标签
    [05]HTML基础之表格标签
    sonarqube启动报错
    rhel6下kvm克隆后的操作登录新克隆的虚拟机重新配置网络
    解决KVM 宿主机redhat6系统上shutdown关不了虚拟机的问题
  • 原文地址:https://www.cnblogs.com/neighthorn/p/6637749.html
Copyright © 2011-2022 走看看