文章标题

单词缩写
树树发现好多计算机中的单词都是缩写,如GDB是全称Gnu DeBug的缩写。但是,有时候缩写对应的全称会不固定,如缩写LINUX可以理解为:

(1) LINus’s UniX

(2) LINUs’s miniX

(3) Linux Is Not UniX

现在树树给出一个单词缩写,以及一个固定的全称(若干个单词组成,空格隔开)。全

称中可能会有无效的单词,需要忽略掉,一个合法缩写要求每个有效单词中至少有一个字符出现在缩写中,所写必须按顺序出现在全称中。

对于给定的缩写和一个固定的全称,问有多少种解释方法?解释方法为所写的每个字母在全称每个有效单词中出现的位置,有一个字母位置不同,就认为是不同的解释方法。
输入输出格式
输入格式:

第一行输入一个N,表示有N个无效单词;

接下来N行分别描述一个由小写字母组成的无效单词;

最后是若干个询问,先给出缩写(只有大写字母),然后给出一个全称,读入以“LAST CASE”结束。

[数据规模]

1≤N≤100,每行字符串长度不超过150,询问次数不超过20,最后方案数不超过10^9。

输出格式

对于每个询问先输出缩写,如果当前缩写不合法,则输出“is not a valid abbreviation”,否则输出“can be formaed in i ways”(i表示解释方法数)

输入样例#1:

2
and
of
ACM academy of computer makers
RADAR radio detection and ranging
LAST CASE

输出样例#1:

ACM can be formed in 2 ways
RADAR is not a valid abbreviation

题解
自然地想到dp
先暴力去掉所有的单词,只对有效单词进行计算(用map)。
用F[i][j][k]表示当前做到缩写的第i位,全称中第j个单词的第k位,有多少种解释方法。
当缩写的第i位第一次出现在第j个单词中:F[i][j][k]+ = F[i-1][j-1][p] (0<=p<=l[j-1])。
或者不是第一次出现F[i][j][k]+ = F[i-1][j][p] (0<=p<=l[j])。
注意
1.两种转移的第p位和第l位都必须是缩写的第i+1位字母的小写形式。最后答案只要枚举缩写最后一个字符出现在全称中最后一个单词的第x位累加起来。
2.”LAST CASE”一定要判全,不然就是90 orz

代码

#include<bits/stdc++.h>
#define F( i,a,b ) for( int i=( a );i<=( b );i++ )
#define F_2( i,a,b ) for( int i=( a );i>=( b );i-- )
#define oo 0x7fffffff
#define LL long long
#define N 201
#define M 10001
using namespace std;

int m,n,k;
int tot,ans,cnt;
int f[N][N][N],l[N],vis[N];
string a[N];
string nxt,s;
map <string,bool> bd;


void dp()
{
    ans=0;
    memset( f,0,sizeof( f ) );
    memset( vis,0,sizeof( vis ) );
    F( i,0,cnt )
    {
        l[i]=a[i].size()-1;
    }
    F( k,0,l[1] )
    {
        if( a[1][k]==a[0][0]-'A'+'a' )
            f[0][1][k]=1;
    }   
    int i=1;
    while( i<=l[0] )
    {
        int minj=min( cnt,i+1 );
        F( j,1,minj )
        {
            F( k,0,l[j] )
            {
                if( a[j][k]==a[0][i]-'A'+'a' )
                {
                        F( p,0,l[j-1] )
                            f[i][j][k]+=f[i-1][j-1][p];
                        F( p,0,k-1 )
                            f[i][j][k]+=f[i-1][j][p];
                }
            }
        }
        i++;
    }
    F( i,0,l[cnt] )
        ans+=f[l[0]][cnt][i];
    if( !ans )
        cout<<a[0]<<" is not a valid abbreviation"<<endl;
    else cout<<a[0]<<" can be formed in "<<ans<<" ways"<<endl;
}

int main()
{
    cin>>n;
    F( i,1,n )
    {
        cin>>s;
        bd.insert(pair<string,int>(s,1));
    }
    cin>>nxt;
    while( 1 )
    {
        a[0]=nxt;
        cnt=0;
        if( a[0]=="LAST" )
        {
            string te;
            cin>>te;
            if( te=="CASE" )
                break;
            else a[++cnt]=te;
        } 
        while( 1 )
        {
            cin>>a[++cnt];
            if( bd[a[cnt]] ) 
            {
                cnt--;
                continue;
            }
            if( a[cnt][0]<'a' )
            {
                nxt=a[cnt];
                cnt--;
                dp();
                break;
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值