• 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

     
  • 相关阅读:
    局部测试用例,日常笔记
    软件测试工程师素养(日常笔记)
    Java控件(日常笔记)
    开发大体流程
    sort学习 LeetCode #406 Queue Reconstruction by Height
    MySQL 变量
    [转帖]查看结构体成员的大小和偏移地址的方法
    [转帖]SQL99
    static静态类 静态函数 静态字段
    默认构造函数
  • 原文地址:https://www.cnblogs.com/neighthorn/p/6637749.html
Copyright © 2020-2023  润新知