zoukankan      html  css  js  c++  java
  • [BZOJ5073] [Lydsy1710月赛]小A的咒语 后缀数组+dp+贪心

    题目链接

    首先这种题一看就是dp。

    (dp[i][j])表示(A)序列中到(i)位之前,取了(j)段,在(B)中的最长的长度。

    转移也比较简单

    [dp[i][j] o dp[i+1][j] quad ext{不选} \ dp[i][j] o dp[i+k][j+1] quad a[i+1..i+k]=b[dp[i][j]..dp[i][j]+k] ]

    但是这样做的复杂度肯定不行。

    发现有一个贪心的思路,因为既然我这里已经占用了一次次数了,那么肯定要尽量地多在B中匹配才好。

    所以这里的(k)可以直接取到(LCP(a[i+1],b[dp[i][j]+1]))。中间的点可以直接跳过,不用转移过去。

    #include<bits/stdc++.h>
    using namespace std;
    #define fec(i,x,y) (int i=head[x],y=g[i].to;i;i=g[i].ne,y=g[i].to)
    #define dbg(...) fprintf(stderr,__VA_ARGS__)
    #define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
    #define fi first
    #define se second
    #define pb push_back
    template<typename I>inline void read(I&x){int f=0,c;while(!isdigit(c=getchar()))c=='-'?f=1:0;x=c&15;while(isdigit(c=getchar()))x=(x<<1)+(x<<3)+(c&15);f?x=-x:0;}
    template<typename A,typename B>inline char SMAX(A&a,const B&b){return a<b?a=b,1:0;}
    template<typename A,typename B>inline char SMIN(A&a,const B&b){return a>b?a=b,1:0;}
    typedef long long ll;typedef unsigned long long ull;typedef std::pair<int,int>pii;
    
    const int N=2e5+7,M=100+7,LOG=20;
    int T,n,m,p,ans;char a[N],b[N],s[N];
    int dp[N][M];
    
    int sa[N],rk[N],sec[N],tax[N],h[N];
    inline void Make_SA(char*s,int n){
    	int m=26,*rnk=rk,*sc=sec;
    	for(int i=1;i<=m;++i)tax[i]=0;
    	for(int i=1;i<=n;++i)tax[rnk[i]=s[i]]++;
    	for(int i=1;i<=m;++i)tax[i]+=tax[i-1];
    	for(int i=n;i;--i)sa[tax[rnk[i]]--]=i;
    	for(int k=1;k<=n;k<<=1){
    		int p=0;
    		for(int i=n-k+1;i<=n;++i)sc[++p]=i;
    		for(int i=1;i<=n;++i)if(sa[i]>k)sc[++p]=sa[i]-k;
    		for(int i=1;i<=m;++i)tax[i]=0;
    		for(int i=1;i<=n;++i)tax[rnk[sc[i]]]++;
    		for(int i=1;i<=m;++i)tax[i]+=tax[i-1];
    		for(int i=n;i;--i)sa[tax[rnk[sc[i]]]--]=sc[i];
    		swap(rnk,sc);p=rnk[sa[1]]=1;
    		for(int i=2;i<=n;++i)rnk[sa[i]]=(sc[sa[i]]==sc[sa[i-1]]&&sc[sa[i]+k]==sc[sa[i-1]+k]?p:++p);
    		if(p>=n)break;else m=p;
    	}
    	for(int i=1;i<=n;++i)rk[sa[i]]=i;
    }
    inline void Make_h(char*s,int n){
    	for(int i=1,f=0;i<=n;++i){
    		if(f)f--;int j=sa[rk[i]-1];
    		while(i+f<=n&&j+f<=n&&s[i+f]==s[j+f])++f;
    		h[rk[i]]=f;
    	}
    }
    
    int f[N][LOG];
    inline void RMQ_init(int n){
    	for(int i=1;i<=n;++i)f[i][0]=h[i];
    	for(int j=1;(1<<j)<=n;++j)
    		for(int i=1;i+(1<<j)-1<=n;++i)
    			f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
    }
    inline int Min(int l,int r){int k=__lg(r-l+1);return min(f[l][k],f[r-(1<<k)+1][k]);}
    inline int LCP(int x,int y,int n=::n+m){if(x==y)return n-x+1;x=rk[x],y=rk[y];if(x>y)swap(x,y);return Min(x+1,y);}
    
    inline void DP(){
    	for(int i=0,k;i<n;++i)
    		for(int j=0;j<=p;++j)
    			SMAX(dp[i+1][j],dp[i][j]),
    			k=min(n-i,LCP(i+1,dp[i][j]+n+1)),
    			j<p&&SMAX(dp[i+k][j+1],dp[i][j]+k);
    }
    
    inline void CSH(){
    	memset(dp,0,sizeof(dp));
    	ans=0;
    }
    int main(){
    	#ifdef hzhkk
    	freopen("hkk.in","r",stdin);
    	#endif
    	read(T);
    	while(T--){
    		CSH();
    		read(n),read(m),read(p);
    		scanf("%s%s",a+1,b+1);
    		for(int i=1;i<=n;++i)s[i]=a[i]-'a'+1;
    		for(int i=1;i<=m;++i)s[i+n]=b[i]-'a'+1;
    		Make_SA(s,n+m);Make_h(s,n+m);
    		RMQ_init(n+m);
    		DP();
    		for(int i=1;i<=p;++i)SMAX(ans,dp[n][i]);
    		if(ans>=m)printf("YES
    ");
    		else printf("NO
    ");
    	}
    }
    
  • 相关阅读:
    ajax的一些知识
    前端性能优化汇总
    jquery实现一些小动画二
    python简单日志处理
    逆波兰式---C实现
    java常见异常
    Hive与HBase集成及常见问题解决
    SQL for HBase
    Demystifying the Skip Scan in Phoenix
    Difference between DDL, DML and DCL commands
  • 原文地址:https://www.cnblogs.com/hankeke/p/BZOJ5073.html
Copyright © 2011-2022 走看看