蒟蒻也能写出来的AC代码!这题好坑啊QAQ,我写的时候输入写了一个小时,too many or too few lines又调了好久好久,状态转移方程还是抄的书。
设计状态转移方程的时候,如果是根据已知求当下会比较难设计,如果根据已知更新未知就相对好设计一些。我们拿
dp[i][j][k]
表示做到缩写中的前
i
位,单词中的前
j−1
个单词外带第
j
个单词的前
k
位的合法的方案数,其中缩写中的第
i
位与第
j
个单词的第
k
位匹配。
显然从 dp[i][j][k] 可以做出两种转移:
- 转移到这个单词的第
l
位,其中
l>k
,且第
j
个单词的第
l
位是与缩写的第
i+1
位匹配的。即
dp[i+1][j][l]+=dp[i][j][k];
- 转移到下一个单词的第
l
位,其中第
j+1
个单词的第
l
位是与缩写的第
i+1
位匹配的。即
dp[i+1][j+1][k]+=dp[i][j][k];
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
struct Words{
int len;
char a[155];
}words[155], useless[105], e[2];
int n, cnt, dp[155][155][155], sum;
char ch[250];
bool deng(Words &x, Words &y){
if(x.len!=y.len) return false;
for(int i=1; i<=x.len; i++)
if(x.a[i]!=y.a[i]) return false;
return true;
}//判断两个单词是否相等
bool work(){
cnt = 0;//表示单词数
char c=getchar();
int len=0;
while (!((c>='a'&&c<='z') || (c>='A'&&c<='Z') || c==' ')) c=getchar();
while ((c>='a'&&c<='z') || (c>='A'&&c<='Z') || c==' '){
ch[len++] = c;
c = getchar();
}
memset(words[0].a, 0, sizeof(words[0].a));
words[0].len = 0;
for(int i=0; i<len; i++){
if((ch[i]>='a' && ch[i]<='z') || (ch[i]>='A' && ch[i]<='Z'))
words[cnt].a[++words[cnt].len] = ch[i];
else{
for(int i=1; i<=n; i++)
if(deng(words[cnt], useless[i])){
cnt--;
break;
}
cnt++;
words[cnt].len = 0;
memset(words[cnt].a, 0, sizeof(words[cnt].a));
}
}
for(int i=1; i<=n; i++)
if(deng(words[cnt], useless[i])){
cnt--;
break;
}
//对最后一个单词的合法性进行检验
if(deng(words[0], e[0]) && deng(words[1], e[1])) return false;
memset(dp, 0, sizeof(dp));
char check[155];
int checklen=words[0].len;
for(int i=1; i<=words[0].len; i++)
check[i] = words[0].a[i] - 'A' + 'a';
dp[0][0][1] = 1;
for(int i=0; i<checklen; i++)
for(int j=0; j<=cnt; j++)
for(int k=1; k<=words[j].len; k++)
if(dp[i][j][k]){//小小优化
for(int l=k+1; l<=words[j].len; l++)
if(words[j].a[l]==check[i+1])
dp[i+1][j][l] += dp[i][j][k];
if(j<cnt)//要是j=cnt就肯定不用再往下一个单词扩展了,因为下一个单词都没了……
for(int l=1; l<=words[j+1].len; l++)
if(words[j+1].a[l]==check[i+1])
dp[i+1][j+1][l] += dp[i][j][k];
}
sum = 0;
for(int i=1; i<=words[cnt].len; i++)
if(check[checklen]==words[cnt].a[i])
sum += dp[checklen][cnt][i];//统计答案
if(sum) printf("%s can be formed in %d ways\n", words[0].a+1, sum);
else printf("%s is not a valid abbreviation\n", words[0].a+1);
return true;
}
int main(){
cin>>n;
e[0].a[1] = 'L';e[0].a[2] = 'A';e[0].a[3] = 'S';e[0].a[4] = 'T';
e[1].a[1] = 'C';e[1].a[2] = 'A';e[1].a[3] = 'S';e[1].a[4] = 'E';
e[0].len = e[1].len = 4;
for(int i=1; i<=n; i++){
scanf("%s", useless[i].a+1);
useless[i].len = strlen(useless[i].a+1);
}
while(work()) ;
return 0;
}