zoukankan      html  css  js  c++  java
  • SNOI2020 LOJ3326 字符串

    题目传送门

    分析:
    (有生之年考场上会做的后缀数组题
    (后缀数组是个好东西,我有头发的时候天天写

    把两个串接在一起,中间隔一个分隔符
    (sa)(height)跑出来
    把我们所需要配对的子串首位置的(rk)位置标记
    两个子串(s1,s2)匹配代价为(K-lcp(s1,s2))
    转化为区间(height)最小值
    于是变成了这样一个问题。。
    数轴上有红蓝两种点,两两匹配价值为两点之间单位线段权值的最小值
    要求价值最大
    做法很经典了,把线段从大到小排序,并查集合并计算就好了。。
    wdnmd,(height)最小值没和(K)取min,竟然能混70分???
    (出题人用脚造数据(划去)

    哦好像后缀自动机也能做
    反向广义后缀自动机建出来,两个子串配对价值为LCA的len
    (O(n))胡乱DP一顿(口胡)

    代码是后缀数组

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<cstdio>
    #include<queue>
    #include<string>
    
    #define maxn 300005
    #define MOD 1000000007
    #define INF 0x3f3f3f3f
     
    using namespace std;
     
    inline int getint()
    {
        int num=0,flag=1;char c;
        while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
        while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
        return num*flag;
    }
    
    int N,n,m,K;
    int sa[maxn],rk[maxn],tp[maxn],tax[maxn],hght[maxn];
    char s[maxn];
    int mn[maxn][19],lg[maxn];
    int f[maxn],sz1[maxn],sz2[maxn],id[maxn];
    long long ans;
    inline bool cmp(int x,int y){return hght[x]>hght[y];}
    inline int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
    
    inline void Rsort()
    {
    	for(int i=0;i<=m;i++)tax[i]=0;
    	for(int i=1;i<=n;i++)tax[rk[tp[i]]]++;
    	for(int i=1;i<=m;i++)tax[i]+=tax[i-1];
    	for(int i=n;i;i--)sa[tax[rk[tp[i]]]--]=tp[i];
    }
    inline bool check(int x,int y,int k)
    {return tp[x]==tp[y]&&tp[x+k]==tp[y+k];}
    
    inline void getsa()
    {
    	for(int i=1;i<=n;i++)rk[i]=s[i],tp[i]=i;
    	m=127,Rsort();
    	for(int p=1,w=1;p<n;w<<=1,m=p)
    	{
    		p=0;
    		for(int i=n-w+1;i<=n;i++)tp[++p]=i;
    		for(int i=1;i<=n;i++)if(sa[i]>w)tp[++p]=sa[i]-w;
    		Rsort(),swap(rk,tp),rk[sa[1]]=p=1;
    		for(int i=2;i<=n;i++)rk[sa[i]]=check(sa[i],sa[i-1],w)?p:++p;
    	}
    	int k=0;
    	for(int i=1;i<=n;i++)
    	{
    		k=k?k-1:k;
    		for(int j=sa[rk[i]-1];s[i+k]==s[j+k];k++);
    		hght[rk[i]]=k;
    	}
    }
    
    inline int query(int l,int r)
    {
    	int k=lg[r-l+1];
    	return min(mn[l][k],mn[r-(1<<k)+1][k]);
    }
    
    inline int getlcp(int x,int y)
    {
    	if(x>y)swap(x,y);
    	if(x==y)return n-sa[x]+1;
    	return query(x+1,y);
    }
    
    int main()
    {
    	for(int i=0;i<19;i++)lg[1<<i]=i;
    	for(int i=1;i<maxn;i++)lg[i]=max(lg[i],lg[i-1]);
    	N=n=getint(),K=getint();
    	scanf("%s",s+1);s[n+1]='#';
    	scanf("%s",s+n+2);
    	n=strlen(s+1);
    	getsa();
    	for(int i=1;i<=n;i++)f[i]=id[i]=i;
    	sort(id+1,id+n+1,cmp);
    	for(int i=1;i<=n;i++)mn[i][0]=hght[i];
    	for(int j=1;j<19;j++)for(int i=1;i+(1<<(j-1))<=n;i++)mn[i][j]=min(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
    	for(int i=1;i<=N-K+1;i++)sz1[rk[i]]=1;
    	for(int i=1;i<=N-K+1;i++)sz2[rk[i+N+1]]=1;
    	for(int i=1;i<=n;i++)
    	{
    		int p=id[i];if(p==1)continue;
    		int u=find(p-1),v=find(p);
    		f[v]=u,sz1[u]+=sz1[v],sz2[u]+=sz2[v];
    		int tmp=min(sz1[u],sz2[u]);
    		ans+=1ll*tmp*(K-min(hght[p],K));
    		sz1[u]-=tmp,sz2[u]-=tmp;
    	}
    	printf("%lld
    ",ans);
    }
    

  • 相关阅读:
    linux之参数实用讲解
    Linux脚本中调用SQL,RMAN脚本
    shell for参数
    Linux Shell参数替换
    Python OOP(1)
    Python 不可变对象
    Python set
    Python tuple
    Python list,tuple,dict and set
    Python 可变长度函数参数
  • 原文地址:https://www.cnblogs.com/Darknesses/p/13208488.html
Copyright © 2011-2022 走看看