最近经常性地在关键时刻掉链子。古希腊先哲说,人不会两次跌进同一个坑——确实,我跌进了两个坑,摔的鼻青脸肿。先是在杭电邀请赛上看错范围,把辅助数组开小,幸好同伴火眼金睛;这道题犯的错误几乎一摸一样,一个a[601][101]的数组开成了a[101][601]。最可恨的是这样的错误假如没有意识到,一辈子都找不出来!ZOJ上wrong answer映的我发绿,莫名其妙,怎么也该打出一个RunTimeError吧……结果我的程序几乎被改成BusyCai同学的程序了……
这类词典型的dp题目倒也差不多,a[i][k]代表了第k个词语在填入第i个位置时的可能总数。只要扫描上一个位置的所有M词语a[i- 1][j],满足情况者加入a[i][k]即可。BusyCai的写法比较好,用每个位置a[i][k]去加到下一个位置a[i + 1][j]。a[i][k]可能为0,节省了很多时间。
#include <cstdio>
#include <string>
int N, L, M, len, a[110][610];
char str[610][11];
void init ()
{
int i;
for ( i = 0; i < M; i ++ )
{
scanf ( "%s", str[i] );
}
memset ( a, 0, sizeof ( a ) );
len = strlen ( str[0] );
}
int check ( int a, int b )
{
int i;
for ( i = 1; i < len; i ++ )
{
if ( str[a][i] != str[b][i - 1] )
return 0;
}
return 1;
}
void dp ()
{
int i, k, j;
for ( k = 0; k < M; k ++ )
{
a[len][k] = 1;
}
for ( i = len; i < L; i ++ )
{
for ( k = 0; k < M; k ++ )
{
if ( a[i][k] )
for ( j = 0; j < M; j ++ )
{
if ( check ( k, j ) )
a[i + 1][j] += a[i][k];
}
}
}
int sum = 0;
for ( k = 0; k < M; k ++ )
{
sum += a[L][k];
}
printf ( "%d\n", sum );
}
int main ()
{
//freopen ( "in.txt", "r", stdin );
while ( scanf ( "%d%d%d", &N, &L, &M ) != EOF )
{
if ( N + L + M == 0 )
break;
init ();
dp ();
//pa ();
}
return 0;
}
评论