[HAOI2008] 玩具取名 - 区间dp

某人有一套玩具,并想法给玩具命名。首先他选择WING四个字母中的任意一个字母作为玩具的基本名字。然后他会根据自己的喜好,将名字中任意一个字母用“WING”中任意两个字母代替,使得自己的名字能够扩充得很长。现在,他想请你猜猜某一个很长的名字,最初可能是由哪几个字母变形过来的。\(n \leq 200\)

Solution

老生常谈的区间 dp

\(f[i][j][k]\) 表示能否将 \([i,j]\) 压成 \(k\) 这个字母,\(g[i][j][k]\) 表示 \(i,j\) 这两个字母能否合成 \(k\) 这个字母,则
\[ f[i][k][p] \and f[k+1][j][q] \and g[p][q][l] \to f[i][j][l] \]
边界 \(f[i][i][?]=1\)

暴力转移即可

#include <bits/stdc++.h>
using namespace std;

const int N = 205;

int f[N][N][4],g[4][4][4],n,a[N],m[4];

int tr(char c) {
    if(c=='W') return 0;
    if(c=='I') return 1;
    if(c=='N') return 2;
    if(c=='G') return 3;
}

signed main() {
    string str;
    for(int i=0;i<4;i++) cin>>m[i];
    for(int i=0;i<4;i++) {
        for(int j=1;j<=m[i];j++) {
            cin>>str;
            g[tr(str[0])][tr(str[1])][i]=1;
        }
    }
    cin>>str;
    n=str.length();
    for(int i=1;i<=n;i++) a[i]=tr(str[i-1]);
    for(int i=1;i<=n;i++) f[i][i][a[i]]=1;
    for(int le=2;le<=n;le++) {
        for(int i=1;i+le-1<=n;i++) {
            int j=i+le-1;
            for(int k=i;k<j;k++) {
                for(int p=0;p<4;p++) {
                    for(int q=0;q<4;q++) {
                        for(int l=0;l<4;l++) {
                            f[i][j][l]|=f[i][k][p]&f[k+1][j][q]&g[p][q][l];
                        }
                    }
                }
            }
        }
    }
    int flag = 0;
    if(f[1][n][0]) cout<<"W", flag=1;
    if(f[1][n][1]) cout<<"I", flag=1;
    if(f[1][n][2]) cout<<"N", flag=1;
    if(f[1][n][3]) cout<<"G", flag=1;
    if(flag==0) cout<<"The name is wrong!"<<endl;
}

猜你喜欢

转载自www.cnblogs.com/mollnn/p/12426216.html