P7541 [COCI2009-2010#1] DOBRA 题解
错误思路
暴力搜,搜每个下划线位置的字母,记下划线个数为 $m$,则 $m\le10$,时间复杂度 $O(26^m)$,超时。
正解
思路
很容易想到其实 $5$ 个元音字母没有本质区别,除了 $\texttt{L}$ 外的辅音字母也一样。我们在搜时只需要在下划线处搜:
- 元音字母
- 除 $\texttt{L}$ 外的辅音字母
- $\texttt{L}$
三个情况即可。
需要注意的是: 由于搜元音时,我们可以在下划线处填任意元音字母,所以填元音字母的方案数要乘以 $5$。同理,搜除 $\texttt{L}$ 外的辅音字母时要乘以 $26-5-1=20$。$\texttt{L}$ 就不需要了,因为只可能填 $\texttt{L}$。
代码
#include <iostream>
using namespace std;
string s;
#define isyy(c) (c=='A'||c=='E'||c=='I'||c=='O'||c=='U')//判断是否是元音
long long dfs(int dep,int y,int f,bool L)//y:连续元音个数,f:连续辅音个数,L:当前是否有‘L’
{
if(y>=3||f>=3)
{
return 0;
}
if(s.size()<=dep)
{
return (long long)L;//有‘L’才“令人愉快”
}
long long t=0;
if(s[dep]=='_')
{
//填元音字母
s[dep]='A';//用‘A’代表元音
t+=5*dfs(dep+1,y+1/* 连续元音数量加1 */,0/* 连续辅音数量清0。下同。 */,L);//一共可填5种元音
//填辅音字母
s[dep]='B';//用‘B’代表辅音
t+=20*dfs(dep+1,0,f+1,L);//‘L’特殊考虑,26-5-1=20,一共可填20种辅音
//填‘L’
s[dep]='L';
t+=dfs(dep+1,0,f+1,true);
s[dep]='_';//恢复原状
return t;
}
else//如果不是下划线
{
if(isyy(s[dep]))
{
return dfs(dep+1,y+1,0,L);
}
else
{
if(s[dep]=='L')
{
return dfs(dep+1,0,f+1,true);
}
else
{
return dfs(dep+1,0,f+1,L);
}
}
}
}
int main()
{
cin>>s;
printf("%lld",dfs(0,0,0,false));
return 0;
}
注意
你需要使用 $64$ 位有符号整数。在 C/C++ 中使用
long long
,Pascal 中使用int64
。 ——题面