題目網址:http://acm.hdu.edu.cn/showproblem.php?pid=2243 這題用的是AC自動機加矩陣乘法去做的。首先根據給的詞根建立字典樹,然後建立AC自動機,利用fail指針去構造矩陣。矩陣的意思是不包含詞根的狀態,而把矩陣0行0到sizes-1列的值相加,就是單詞長度爲一時,不包含詞根的情況有多少種。用最大數去減,就是單詞長度爲一時,包含詞根的種數。同樣的,矩陣相乘後,乘了N次,用最大數去減,便是長度爲N的單詞長度包含詞根的情況,把1到N的種類相加便是答案。注意,在這裏的代碼中,我直接把矩陣N階的和表示了出來,所以直接減就是答案。這裏求矩陣N階的和用的是二分法,不然會超時,假設N是一階矩陣,N^4 = N^1 + N^2 + N^2 * (N^1 + N^2).二分法中爲奇數時特殊處理。
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <queue>
#define maxc 35
#define maxn 26
#define mem(a) memset(a, 0, sizeof(a))
using namespace std;
int tree[maxc][maxn], fails[maxc], words[6], sizes;
unsigned __int64 maps[maxc][maxc], ress[maxc][maxc], tmps[maxc][maxc], tmpss[maxc][maxc], danwei[maxc][maxc], ans, rs, rss;
bool num[maxc];
char ch[6];
void inits()
{
sizes = 1;
num[0] = 0;
mem(tree[0]);
mem(maps);
mem(ress);
mem(tmps);
return;
}
void build()
{
int i, a, b = 0;
for(i = 1;i <= words[0];i++)
{
a = words[i];
if(!tree[b][a])
{
mem(tree[sizes]);
num[sizes] = 0;
tree[b][a] = sizes++;
}
b = tree[b][a];
}
num[b] = 1;
return;
}
void ac_machine_build()
{
int i, a, b;
queue<int> q;
fails[0] = 0;
for(i = 0;i < maxn;i++)
{
a = tree[0][i];
if(a)
{
fails[a] = 0;
q.push(a);
}
}
while(!q.empty())
{
b = q.front();
q.pop();
if(num[fails[b]])
num[b] = 1;
for(i = 0;i < maxn;i++)
{
a = tree[b][i];
if(!a)
{
tree[b][i] = tree[fails[b]][i];
continue;
}
q.push(a);
fails[a] = tree[fails[b]][i];
}
}
return;
}
void zh(char *word)
{
int i, len;
len = strlen(word);
words[0] = len;
for(i = 0;i < len;i++)
words[i + 1] = ch[i] - 'a';
return;
}
void mps()
{
int i, j;
mem(maps);
for(i = 0;i < sizes;i++)
{
for(j = 0;j < maxn;j++)
{
if(!num[i]&&!num[tree[i][j]])
maps[i][tree[i][j]]++;
}
}
return;
}
void mp_add(unsigned __int64 a[][maxc], unsigned __int64 b[][maxc])
{
int i, j;
for(i = 0;i < sizes;i++)
{
for(j = 0;j < sizes;j++)
{
a[i][j] = a[i][j] + b[i][j];
}
}
return;
}
void mp_sub(unsigned __int64 a[][maxc], unsigned __int64 b[][maxc])
{
int i, j;
for(i = 0;i < sizes;i++)
{
for(j = 0;j < sizes;j++)
{
a[i][j] = a[i][j] - b[i][j];
}
}
return;
}
void mp_mt(unsigned __int64 a[][maxc], unsigned __int64 b[][maxc], unsigned __int64 c[][maxc])
{
int i, j, k;
for(i = 0;i < sizes;i++)
{
for(j = 0;j < sizes;j++)
{
c[i][j] = 0;
for(k = 0;k < sizes;k++)
{
c[i][j] += (a[i][k] * b[k][j]);
}
}
}
return;
}
void mp_fz(unsigned __int64 a[][maxc], unsigned __int64 b[][maxc])
{
int i, j;
for(i = 0;i < sizes;i++)
{
for(j = 0;j < sizes;j++)
{
a[i][j] = b[i][j];
}
}
return;
}
void mp_swap(unsigned __int64 a[][maxc], unsigned __int64 b[][maxc])
{
int i, j;
unsigned long long c[maxc][maxc];
for(i = 0;i < sizes;i++)
{
for(j = 0;j < sizes;j++)
{
c[i][j] = a[i][j];
}
}
for(i = 0;i < sizes;i++)
{
for(j = 0;j < sizes;j++)
{
a[i][j] = b[i][j];
}
}
for(i = 0;i < sizes;i++)
{
for(j = 0;j < sizes;j++)
{
b[i][j] = c[i][j];
}
}
return;
}
void res(unsigned __int64 n)
{
if(n == 1)
{
int i, j;
for(i = 0;i < sizes;i++)
{
for(j = 0;j < sizes;j++)
{
tmpss[i][j] = ress[i][j] = maps[i][j];
}
}
rs = rss = 26;
return;
}
res(n / 2);
rs = rs * rss + rs;
rss = rss * rss;
unsigned __int64 tp[maxc][maxc];
mp_mt(ress, tmpss, tp);
mp_add(ress, tp);
mp_mt(tmpss, tmpss, tmps);
if(n % 2)
{
rs = (rs + 1) * 26;
rss *= 26;
mp_add(ress, danwei);
mp_mt(ress, maps, tp);
mp_fz(ress, tp);
mp_mt(tmps, maps, tmpss);
}
else
{
mp_swap(tmps, tmpss);
}
}
int main()
{
int i, n;
unsigned __int64 m, tmp;
for(i = 0;i < 35;i++)
{
danwei[i][i] = 1;
}
while(scanf("%d%I64u", &n, &m) != EOF)
{
inits();
ans = 0;
for(i = 0;i < n;i++)
{
mem(ch);
scanf("%s", ch);
zh(ch);
build();
}
ac_machine_build();
mps();
res(m);
for(i = 0;i < sizes;i++)
ans += ress[0][i];
printf("%I64u\n", rs - ans);
}
return 0;
}