DP【洛谷P4290】 [HAOI2008]玩具取名

P4290 [HAOI2008]玩具取名

某人有一套玩具,并想法给玩具命名。首先他选择WING四个字母中的任意一个字母作为玩具的基本名字。然后他会根据自己的喜好,将名字中任意一个字母用“WING”中任意两个字母代替,使得自己的名字能够扩充得很长。

现在,他想请你猜猜某一个很长的名字,最初可能是由哪几个字母变形过来的。

很早以前的考试题。

DP。

重点在预处理出每个区间能否凑成一个字母。

很简单,枚举断点即可。

code:

#include <iostream>
#include <cstdio>
#include <map>
#include <cstring>

using namespace std;

const int wx=251;

map<char,int> m;

inline int read(){
    int sum=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0'; ch=getchar();}
    return sum*f;
}

int f[wx][wx];
int zmj[wx][wx][wx];
int a[wx],flag[wx];
int ok1[wx],ok2[wx],ok3[wx];
char c[wx];
int tot;

int main(){
    m['W']=1; m['I']=2; m['N']=3; m['G']=4;
    for(int i=1;i<=4;i++)a[i]=read();
    for(int i=1;i<=4;i++){
        for(int j=1;j<=a[i];j++){
            scanf("%s",c+1);
            ok1[++tot]=m[c[1]];
            ok2[tot]=m[c[2]];
            ok3[tot]=i;
        }
    }
    scanf("%s",c+1); int n=strlen(c+1);
    for(int i=1;i<=n;i++)zmj[i][i][m[c[i]]]=1;
    for(int len=1;len<=n;len++){
        for(int i=1;i+len-1<=n;i++){
            int j=i+len-1;
            for(int k=i;k<=j;k++){
                for(int l=1;l<=tot;l++){
                    if(zmj[i][k][ok1[l]]&&zmj[k+1][j][ok2[l]]){
                        zmj[i][j][ok3[l]]=1;
                    }
                }
            }
        }
    }
    for(int len=1;len<=n;len++){
        for(int i=1;i+len-1<=n;i++){
            int j=i+len-1;
            for(int l=1;l<=tot;l++){
                if(zmj[i][j][l]){
                    f[i][j]=1;
                    goto zz;
                }
            }
            f[i][j]=0x3f3f3f3f;
            for(int k=i;k<=j;k++){
                f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
            }
            zz:;
        }
    }
    for(int i=1;i<=tot;i++){
        if(zmj[1][n][ok3[i]])flag[ok3[i]]=1;
    }
    int fl=0;
    if(flag[1])printf("W"),fl=1;
    if(flag[2])printf("I"),fl=1;
    if(flag[3])printf("N"),fl=1;
    if(flag[4])printf("G"),fl=1;
    if(!fl)puts("The name is wrong!");
    return 0;
}

转载于:https://www.cnblogs.com/wangxiaodai/p/9879527.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值