暴力dp+状态设计思维——cf1303E

感觉这一题的状态设计很有讲究

一开始的思路是枚举s的前半部分,去贪心的匹配t串,然后再看剩余部分是否可以匹配t的后半部分

但这种思路显然是错的(样例都过不了),原因是可能t后半部分的某个特征串只在s中(对应的一个特征序列)出现了一次,

但是这个s中的特征序列由于被t前半部分贪心的匹配,被打破了,所以不能成功匹配后半部分

后来想到枚举t的前半部分和后半部分,然后用一个二维dp[i][j]去枚举匹配即可

/*
枚举pos:1->T,表示t被分成t[1..pos]和t[pos+1..T]两个串
dp[i][j]表示 t1匹配到i位,t2匹配到j位的最短的s前缀 
*/
#include<bits/stdc++.h>
using namespace std;
#define N 405

char s[N],t[N];
int S,T,dp[N][N],nxt[N][26],pos[26];

void init(){
    for(int i=0;i<26;i++)pos[i]=S+1;
    for(int i=S;i>=0;i--){
        for(int j=0;j<26;j++)
            nxt[i][j]=pos[j];
        if(i)pos[s[i]-'a']=i;
    }
}

char t1[N],t2[N];
int len1,len2;
int solve(int pos){
    for(int i=0;i<=T;i++)
        for(int j=0;j<=T;j++)
            dp[i][j]=0x3f3f3f3f;
    len1=pos,len2=T-pos;
    for(int i=1;i<=len1;i++)t1[i]=t[i];
    for(int i=1;i<=len2;i++)t2[i]=t[i+pos];
    
    dp[0][0]=0;
    for(int i=0;i<=len1;i++)
        for(int j=0;j<=len2;j++){
            if(i==0 && j==0)continue;
            if(i){
                int last=dp[i-1][j];
                if(last<=S)
                    dp[i][j]=min(dp[i][j],nxt[last][t1[i]-'a']);
            }
            if(j){
                int last=dp[i][j-1];
                if(last<=S)
                    dp[i][j]=min(dp[i][j],nxt[last][t2[j]-'a']);
            }
        }
    if(dp[len1][len2]<=S)return 1;
    return 0;
}

int main(){
    int tt;cin>>tt;
    while(tt--){
        scanf("%s%s",s+1,t+1);
        S=strlen(s+1);
        T=strlen(t+1);
        init();
        
        int flag=0;
        for(int i=1;i<=T;i++) 
            if(solve(i))flag=1;
        if(flag)puts("YES");
        else puts("NO");
    }    
} 

猜你喜欢

转载自www.cnblogs.com/zsben991126/p/12311230.html