BZOJ 4698: Sdoi2008 Sandy的卡片

一直在想要不要把这篇题解删掉
是上面那题的加强版,数据范围变大了,题目要求也稍微改动了一下。
其实我们只要把原数组变成一个差量数组,同时在哈希的时候,避免负数就好了。
时间复杂度:O(log2(m) nm log2(nm))
#include <bits/stdc++.h>
#define int unsigned long long
using namespace std;
const int N=1e3+5,M=105,base=131;
int n,l,r,mid,ans;
int len[N],hash[N][M],sum[N][M],bin[M],num[M];
map<int,bool>mp[N];

inline int get(int x,int y,int id){return hash[id][y]-hash[id][x-1]*bin[y-x+1];}

inline void init()
{
	for (register int i=1; i<=n; ++i)
	for (register int j=1; j<=len[i]-mid+1; ++j) mp[i][sum[i][j]]=false;
}

inline bool jay(int mid)
{
	for (register int i=1; i<=n; ++i)
	for (register int j=1; j<=len[i]-mid+1; ++j) sum[i][j]=get(j,j+mid-1,i),mp[i][sum[i][j]]=true;
	
	for (register int i=1; i<=len[1]-mid+1; ++i)
	{
		bool flag=true;
		for (register int j=2; j<=n; ++j) if (!mp[j][sum[1][i]]) {flag=false; break;}	
		if (flag) 
		{
			init();
			return true;	
		}
	}
	init();
	return false;
}

signed main(){
	scanf("%lld",&n);
	l=1e9; r=0;
	for (register int i=1; i<=n; ++i)
	{
		scanf("%lld",&len[i]);
		for (register int j=1; j<=len[i]; ++j) scanf("%lld",&num[j]);
		len[i]--;
		l=min(l,len[i]); r=max(r,len[i]);
		for (register int j=1; j<=len[i]; ++j) num[j]=num[j]-num[j+1]+2000;
		for (register int j=1; j<=len[i]; ++j) hash[i][j]=hash[i][j-1]*base+num[j];
	}
	
	bin[0]=1;
	for (register int i=1; i<=r; ++i) bin[i]=bin[i-1]*base;
	r=l; l=1;
	while (l<=r)
	{
		mid=l+r>>1;
		if (jay(mid)) ans=mid,l=mid+1;
		else r=mid-1;
	}
	ans++;
	printf("%lld\n",ans);
return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值