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

    BZOJ权限题qwq
    Luogu

    sol

    “两个子串长度相同且一个串的全部元素加上一个数就会变成另一个串”
    其实就是差分一波以后完全相同
    所以对输入的数据进行差分,同时记一下每一个位置是属于哪个串的。
    记得在串与串中间加入一个没有出现的字符。
    求出SA后二分答案(mid),问题变成:(Height)数组里是否存在一个大于等于(mid)的连续段使每个串都在里面出现过。
    开桶记录。记一个(id)避免每次对桶的清空。

    code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    using namespace std;
    #define ll long long
    int gi()
    {
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    const int N = 1e6+1e4+5;
    int n,tot,a[N],b[N],t[N],x[N],y[N],SA[N],Rank[N],Height[N],id;
    bool cmp(int i,int j,int k){return y[i]==y[j]&&y[i+k]==y[j+k];}
    void getSA()
    {
    	int m=1e6+1e4;
    	for (int i=1;i<=n;++i) ++t[x[i]=a[i]];
    	for (int i=1;i<=m;++i) t[i]+=t[i-1];
    	for (int i=n;i>=1;--i) SA[t[x[i]]--]=i;
    	for (int k=1;k<=n;k<<=1)
    	{
    		int p=0;
    		for (int i=0;i<=m;++i) y[i]=0;
    		for (int i=n-k+1;i<=n;++i) y[++p]=i;
    		for (int i=1;i<=n;++i) if (SA[i]>k) y[++p]=SA[i]-k;
    		for (int i=0;i<=m;++i) t[i]=0;
    		for (int i=1;i<=n;++i) ++t[x[y[i]]];
    		for (int i=1;i<=m;++i) t[i]+=t[i-1];
    		for (int i=n;i>=1;--i) SA[t[x[y[i]]]--]=y[i];
    		swap(x,y);
    		x[SA[1]]=p=1;
    		for (int i=2;i<=n;++i) x[SA[i]]=cmp(SA[i],SA[i-1],k)?p:++p;
    		if (p>=n) break;
    		m=p;
    	}
    	for (int i=1;i<=n;++i) Rank[SA[i]]=i;
    	for (int i=1,j=0;i<=n;++i)
    	{
    		if (j) --j;
    		while (a[i+j]==a[SA[Rank[i]-1]+j]) ++j;
    		Height[Rank[i]]=j;
    	}
    }
    bool check(int mid)
    {
    	++id;int cnt=0;
    	for (int i=1;i<=n;++i)
    		if (Height[i]>=mid)
    		{
    			if (t[b[SA[i-1]]]!=id) t[b[SA[i-1]]]=id,++cnt;
    			if (t[b[SA[i]]]!=id) t[b[SA[i]]]=id,++cnt;
    			if (cnt==tot) return true;
    		}
    		else cnt=0,++id;
    	return false;
    }
    int main()
    {
    	tot=gi();
    	for (int i=1;i<=tot;++i)
    	{
    		for (int j=1,len=gi();j<=len;++j)
    			t[j]=gi(),a[++n]=t[j]-t[j-1]+5e5,b[n]=i;
    		a[++n]=1e6+i;
    	}
    	memset(t,0,sizeof(t));
    	getSA();
    	memset(t,0,sizeof(t));
    	int l=0,r=n;
    	while (l<r)
    	{
    		int mid=l+r+1>>1;
    		if (check(mid)) l=mid;
    		else r=mid-1;
    	}
    	printf("%d
    ",l+1);
    	return 0;
    }
    
    
  • 相关阅读:
    http2
    JMH java基准测试
    java 线程池
    线程中断
    mybatis
    JDBC 线程安全 数据库连接池
    mysql string 列类型
    剖析nsq消息队列目录
    go微服务框架go-micro深度学习-目录
    详说tcp粘包和半包
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8467787.html
Copyright © 2011-2022 走看看