【BZOJ5073】[Lydsy十月月賽]小A的咒語
題解:沙茶DP,完全不用后綴數組。
用f[i][j]表示用了A的前i個字符,用了j段,最遠能匹配到哪。因為顯然我們能匹配到的地方越遠越好,所以我們直接判斷A[i]和B[f[i][j]]是否相等,如果相等則轉移下去。還要記錄g[i][j]表示第i個字符匹配成功時最遠能匹配到哪,這樣f數組可以求前綴最大值,但要從j轉移到j+1,而g數組可以從j轉移到j。
P.S:貪心策略好像有bug。。。大家還是寫后綴數組吧。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn=100010;
int n,m,K,T,ans;
char s1[maxn],s2[maxn];
int f[maxn][110],g[maxn][110];
void work()
{
scanf("%d%d%d%s%s",&n,&m,&K,s1,s2),ans=0;
int i,j;
memset(f,0,sizeof(f)),memset(g,0xc0,sizeof(g));
for(i=0;i<n;i++)
{
for(j=0;j<=K;j++)
{
if(f[i][j]==m||g[i][j]==m)
{
printf("YES\n");
return ;
}
f[i][j]=max(f[i][j],g[i][j]);
if(s1[i]==s2[f[i][j]]) g[i+1][j+1]=max(g[i+1][j+1],f[i][j]+1);
if(g[i][j]>=0&&s1[i]==s2[g[i][j]]) f[i+1][j+1]=max(f[i+1][j+1],g[i][j]+1),g[i+1][j]=max(g[i+1][j],g[i][j]+1);
f[i+1][j]=max(f[i+1][j],f[i][j]);
}
}
for(j=0;j<=K;j++) if(f[n][j]==m||g[n][j]==m)
{
printf("YES\n");
return ;
}
printf("NO\n");
}
int main()
{
scanf("%d",&T);
while(T--) work();
return 0;
}//1 9 6 3 hloyaygrt loyyrt
