luogu P2463 [SDOI2008]Sandy的卡片 |二分+hash

题目描述

Sandy和Sue的热衷于收集干脆面中的卡片。

然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积攒卡片兑换超炫的人物模型。

每一张卡片都由一些数字进行标记,第i张卡片的序列长度为Mi,要想兑换人物模型,首先必须要集够N张卡片,对于这N张卡片,如果他们都有一个相同的子串长度为k,则可以兑换一个等级为k的人物模型。相同的定义为:两个子串长度相同且一个串的全部元素加上一个数就会变成另一个串。

Sandy的卡片数远远小于要求的N,于是Sue决定在Sandy的生日将自己的卡片送给Sandy,在Sue的帮助下,Sandy终于集够了N张卡片,但是,Sandy并不清楚他可以兑换到哪个等级的人物模型,现在,请你帮助Sandy和Sue,看看他们最高能够得到哪个等级的人物模型。
输入格式

第一行为一个数N,表示可以兑换人物模型最少需要的卡片数,即Sandy现在有的卡片数

第i+1行到第i+N行每行第一个数为第i张卡片序列的长度Mi,之后j+1到j+1+Mi个数,用空格分隔,分别表示序列中的第j个数
输出格式

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


先差分一下序列,然后二分长度,hash判断

#include<bits/stdc++.h>
#define g 1897
#define ull unsigned long long
using namespace std;
#define _ 1041
int n,s[_];
ull hash[_][_],jc[_];
map<ull,long long>vis;
map<ull,bool>rhs;
inline bool check(int mid){
	vis.clear();
	for(int i=1;i<n;i++){
		int len=s[i];
		rhs.clear();
		vis[hash[i][mid-1]]++;
		rhs[hash[i][mid-1]]=1;
		for(int j=mid;j<len;j++){
			ull sum=hash[i][j]-hash[i][j-mid]*jc[mid];
			if(!rhs[sum])vis[sum]++,rhs[sum]=1;
		}
	}
	if(vis[hash[n][mid-1]]==n-1)return 1;
	int len=s[n];
	for(int i=mid;i<len;i++){
		ull sum=hash[n][i]-hash[n][i-mid]*jc[mid];
		if(vis[sum]==n-1)return 1;
	}
	return 0;
}
int a[_];
signed main() {
	scanf("%d",&n);
	jc[0]=1; for(int i=1;i<=1001;i++)jc[i]=jc[i-1]*g;
	int l=0,r=1001,ans=-1;
	for(int i=1;i<=n;i++){
		scanf("%d",&s[i]);
		for(int j=0;j<s[i];j++){
			scanf("%d",&a[j]);
			if(j)hash[i][j]=a[j]-a[j-1],hash[i][j]+=hash[i][j-1]*g;
		    else hash[i][j]=a[j];
		    
		}
		r=min(r,s[i]);
	}
	
	while(l<=r){
		int mid=(l+r)>>1;
		if(check(mid)){
			l=mid+1;
			ans=mid;
		}else r=mid-1;
	}
	cout<<ans+1<<endl;
	return 0;
}
posted @ 2020-01-07 15:11  白木偶君  阅读(124)  评论(0编辑  收藏  举报