[BZOJ5073] [Lydsy1710月賽]小A的咒語 字尾陣列+dp+貪心
阿新 • • 發佈:2019-01-06
首先這種題一看就是dp。
設\(dp[i][j]\)表示\(A\)序列中到\(i\)位之前,取了\(j\)段,在\(B\)中的最長的長度。
轉移也比較簡單
\[ dp[i][j] \to dp[i+1][j] \quad \text{不選} \\ dp[i][j] \to 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\n"); else printf("NO\n"); } }