zoukankan      html  css  js  c++  java
  • luoguP2463 [SDOI2008]Sandy的卡片

    题意

    显然加上一个数相等就是差分数组相等,于是问题变为求几个串的最长公共子串。

    这里我学习了如何用SA求LCS。

    首先问题要转化成求一些后缀的最长公共前缀,要求这些后缀分属不同的串。

    于是二分答案,于是问题就变成求一段连续的(height)数组,它们都(geqslant mid),并且至少分属(n)个串,显然可以(O(n))扫一遍得出。

    code:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+10;
    int n,num,K;
    int a[maxn],b[maxn],pos[maxn];
    int sa[maxn],rk[maxn],oldrk[maxn],id[maxn],tmpid[maxn],cnt[maxn],height[maxn];
    bool vis[maxn];
    inline bool cmp(int x,int y,int k){return oldrk[x]==oldrk[y]&&oldrk[x+k]==oldrk[y+k];}
    inline void sa_build()
    {
    	num=3000;
    	for(int i=1;i<=n;i++)cnt[rk[i]=a[i]]++;
    	for(int i=1;i<=num;i++)cnt[i]+=cnt[i-1];
    	for(int i=n;i;i--)sa[cnt[rk[i]]--]=i;
    	for(int t=1;t<=n;t<<=1)
    	{
    		int tot=0;
    		for(int i=n-t+1;i<=n;i++)id[++tot]=i;
    		for(int i=1;i<=n;i++)if(sa[i]>t)id[++tot]=sa[i]-t;
    		tot=0;
    		memset(cnt,0,sizeof(cnt));
    		for(int i=1;i<=n;i++)cnt[tmpid[i]=rk[id[i]]]++;
    		for(int i=1;i<=num;i++)cnt[i]+=cnt[i-1];
    		for(int i=n;i;i--)sa[cnt[tmpid[i]]--]=id[i];
    		memcpy(oldrk,rk,sizeof(rk));
    		for(int i=1;i<=n;i++)rk[sa[i]]=cmp(sa[i-1],sa[i],t)?tot:++tot;
    		num=tot;
    		if(num>=n)break;
    	}
    	for(int i=1,j=0;i<=n;i++)
    	{
    		if(j)j--;
    		while(a[i+j]==a[sa[rk[i]-1]+j])j++;
    		height[rk[i]]=j;
    	}
    }
    inline bool work(int l,int r)
    {
    	if(r-l+1<K)return 0;
    	int tot=0;
    	memset(vis,0,sizeof(vis));
    	for(int i=l;i<=r;i++)
    		if(!vis[pos[sa[i]]])
    			tot++,vis[pos[sa[i]]]=1;
    	return tot==K;
    }
    inline bool check(int mid)
    {
    	int l=1,r=1;
    	while(l<=n)
    	{
    		while(height[r+1]>=mid&&r<n)r++;
    		if(work(l,r))return 1;
    		l=r+1;r=l;
    	}
    	return 0;
    }
    const int delta=1900; 
    int main()
    {
    	scanf("%d",&K);
    	for(int i=1;i<=K;i++)
    	{
    		int k;scanf("%d",&k);
    		for(int j=0;j<k;j++)scanf("%d",&b[j]);
    		for(int j=1;j<k;j++)a[++n]=b[j]-b[j-1],pos[n]=i;
    		a[++n]=i+delta;pos[n]=i;
    	}
    	sa_build();
    	int l=0,r=n,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);//+1!!!
    	return 0;
    }
    
  • 相关阅读:
    《MySQL是怎样运行的:从根儿上理解MySQL》笔记4
    《MySQL是怎样运行的:从根儿上理解MySQL》笔记3
    推荐一个对比jar包依赖的工具
    《MySQL是怎样运行的:从根儿上理解MySQL》笔记2
    《MySQL是怎样运行的:从根儿上理解MySQL》笔记1
    查询异步更新状态的一种思路
    springAop:Aop(Xml)配置,Aop注解配置,spring_Aop综合案例,Aop底层原理分析
    java知识点总结
    Maven基础&&Spring框架阶段常用工具类整理
    Idea快捷键整理
  • 原文地址:https://www.cnblogs.com/nofind/p/12056985.html
Copyright © 2011-2022 走看看