题意:给你 n 个单词,求出满足以下条件的单词个数:长度不大于 L 且单词中至少包含一个子串为前面 n 个单词中任意一个。先求出所有单词的数量 26^1+ 26^2+ ... + 26^L,可以用矩阵乘法求出,也可用逆元的方法。然后求出所有不包含 n 个单词的串的数量,这个求法和 pku 2778 相同,只是这里要求出所有长度不大于 L 的字符串数量和,方法参考 pku 3233。两者相减就是答案。对那个 2^64 求余,用unsigned __int64 存储的数据,相乘溢出后剩下的结果,就直接是对2^64取模的结果。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
typedef unsigned __int64 ULL;
int N, L;
struct Node{
int next[26];
int fail, flag;
void init(){
for( int i= 0; i< 26; ++i ) next[i]= 0;
fail= -1; flag= 0;
}
}tb[100];
char str[100];
int cnt= 0;
ULL mat[100][100], A[100][100], B[100][100];
void insert( char*s ){
int rt= 0;
while( *s ){
int t= *s- 'a';
if( tb[rt].next[t]== 0 ){
tb[++cnt].init();
tb[rt].next[t]= cnt;
}
rt= tb[rt].next[t]; s++;
}
tb[rt].flag= 1;
}
void bfs(){
int que[1000], head= 0, tail= 0; que[0]= 0;
int p, q;
while( head<= tail ){
int now= que[head++];
for( int t= 0; t< 26; ++t )
if( tb[now].next[t]!= 0 ){
p= tb[now].next[t]; q= tb[now].fail;
while( q!= -1 && !tb[q].next[t] ) q= tb[q].fail;
if( q== -1 ) tb[p].fail= 0;
else {
tb[p].fail= tb[q].next[t];
tb[p].flag|= tb[ tb[p].fail ].flag;
}
que[++tail]= p;
}
else{
q= tb[now].fail;
while( q!= -1 && !tb[q].next[t] ) q= tb[q].fail;
if( q== -1 ) tb[now].next[t]= 0;
else tb[now].next[t]= tb[q].next[t];
}
}
}
void inline mult( ULL x[100][100], ULL y[100][100], int len ){
ULL z[100][100];
for( int i= 0; i< len; ++i )
for( int j= 0; j< len; ++j ){
z[i][j]= 0;
for( int k= 0; k< len; ++k )
z[i][j]+= x[i][k]* y[k][j];
}
for( int i= 0; i< len; ++i )
for( int j= 0; j< len; ++j )
y[i][j]= z[i][j];
}
ULL getNum(){
for( int i= 0; i< 100; ++i )
for( int j= 0; j< 100; ++j ){
mat[i][j]= 0; A[i][j]= 0; B[i][j]= 0; }
for( int i= 0; i< 100; ++i ) B[i][i]= 1;
for( int i= 0; i<= cnt; ++i )
if( !tb[i].flag )
for( int t= 0; t< 26; ++t )
if( !tb[ tb[i].next[t] ].flag )
mat[i][ tb[i].next[t] ]++;
for( int i= 0; i< cnt; ++i ){
A[i][i]= 1; A[i+cnt][i]= 1;
for( int j= 0; j< cnt; ++j )
A[i+ cnt][j+ cnt]= mat[i][j];
}
int p= L;
while( p ){
if( p& 1 ) mult( A, B, cnt<<1 );
mult( A, A, cnt<<1 ); p>>= 1;
}
for( int i= 0; i< cnt; ++i )
for( int j= 0; j< cnt; ++j ) B[i][j]= B[i+cnt][j];
mult( B, mat, cnt );
ULL res= 0;
for( int i= 0; i< cnt; ++i )
res+= mat[0][i];
return res;
}
ULL totNum(){
mat[0][0]= 1; mat[0][1]= 0;
mat[1][0]= 26; mat[1][1]= 26;
A[0][0]= 1; A[0][1]= 0;
A[1][0]= 0; A[1][1]= 1;
int p= L- 1;
while( p ){
if( p& 1 ) mult( mat, A, 2 );
mult( mat, mat, 2 ); p>>= 1;
}
ULL res= 0;
res= A[0][0]* 26+ A[1][0]* 26;
return res;
}
int main(){
while( scanf("%d%d",&N, &L)!= EOF ){
tb[0].init(); cnt= 0;
for( int i= 0; i< N; ++i ){
scanf("%s", str );
insert( str );
}
bfs();
ULL ans= totNum()- getNum();
if( ans< 0 ) ans= ans+ (1llu<<63)+ (1llu<<63);
printf("%I64u\n", ans );
}
return 0;
}