[典藏题记004]E. Erase Subsequences(DP)

非常nice的dp题。
状态是这样的:
t = a + b t=a+b t=a+b
d p [ i ] [ j ] dp[i][j] dp[i][j]表示a字符串填了前 i i i个, b b b字符串填了前 j j j个需要的最小 ∣ s ∣ |s| s长度。
d p [ 0 ] [ 0 ] dp[0][0] dp[0][0]=0
当然我们还需要枚举分界线,即我们想要的 ∣ a ∣ |a| a,如此才可以确定 ∣ b ∣ |b| b的前 j j j个字符到底是什么。
此外,为了
状态转移方程:

i f ( s [ l e n s ] = = b [ l e n a ] ) d p [ l e n a + 1 ] [ l e n b ] = m i n ( d p [ l e n a + 1 , l e n b ] , d p [ l e n a ] [ l e n b ] 转 移 到 新 状 态 的 下 一 个 ∣ S ∣ 长 度 ) if(s[lens]==b[lena])\\ dp[lena+1][lenb]=min(dp[lena+1,lenb],dp[lena][lenb]转移到新状态的下一个|S|长度) if(s[lens]==b[lena])dp[lena+1][lenb]=min(dp[lena+1,lenb],dp[lena][lenb]S)

对于这个更新状态的 ∣ S ∣ |S| S长度,我们需要利用当前状态的最小长度 ( x ) (x) (x)来找。
显然是贪心地选取 s x , s x + 1 , ⋯ ( 0 − i n d e x e d ) s_x,s_{x+1},\cdots (0-indexed) sx,sx+1,(0indexed)中出现的第一个匹配字符。
预处理出一个 n x t [ p o s ] [ j ] nxt[pos][j] nxt[pos][j]表明 s x , s x + 1 , ⋯ ( 0 − i n d e x e d ) s_x,s_{x+1},\cdots (0-indexed) sx,sx+1,(0indexed)中出现的第一个匹配字符 j j j
l e n b lenb lenb更新同理
复杂度为 O ( n ) ∗ O ( n 2 ) O(n)*O(n^2) O(n)O(n2)枚举断点和双重状态
传送门

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define MAXN 402
#define fore(n) for(ll i=1;i<=n;i++)
ll n,m;
int dp[MAXN][MAXN];
int nxt[MAXN][30];
int pos[30];
int main()
{
    int t;
   // freopen("E://tt.txt","r",stdin);
    cin>>t;
    while(t--)
    {
        string a;
        string b;
        cin>>a>>b;
        n=a.length();
        m=b.length();
        for(int i=0;i<26;i++)
            pos[i]=n+1;
        for(int i=n+1;i>=0;i--)
        {
            for(int j=0;j<26;j++)
            {
                nxt[i][j]=pos[j];
            }
            if(i&&i<=n)pos[a[i-1]-'a']=i;
        }
        int is=0;
        for(int x=0;x<=m;x++)
        {
            for(int i=0;i<=m;i++)
                for(int j=0;j<=m;j++)
                    dp[i][j]=n+1;
            dp[0][0]=0;
            for(int i=0;i<=x;i++)
                for(int j=0;j<=m-x;j++)
                {
                    if(i<m)
                    dp[i+1][j]=min(dp[i+1][j],nxt[dp[i][j]][b[i]-'a']);
                    if(j+x<m)
                    dp[i][j+1]=min(dp[i][j+1],nxt[dp[i][j]][b[j+x]-'a']);
                }
            if(dp[x][m-x]<=n)
                is=1;
        }
        cout<<(is?"YES":"NO")<<endl;
    }
}

你可能感兴趣的:(DP,典藏)