题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2243
题目大意:
给m个字符串,求长度不超过n且包括这m个字符串的字符串个数。
题目思路:
推荐博客:传送门
跟POJ 2778非常像,之前那个题是求不包括的,这里是求包括的,那非常自然就想到可以用所有的情况数减去不包括的情况数。所有的情况数就是长度为1的所有情况+长度为2的…+长度为n的,也就是
26
+
2
6
2
+
.
.
.
2
6
n
26+26^2+...26^n
26+262+...26n,对于矩阵也同样如此,矩阵的获得方法可以看我前面POJ2778的题解:传送门,接下来就是说明如何求得这个次数变大的和
这其实是一个矩阵快速幂的经典问题,对于矩阵
∣
A
1
0
1
∣
∗
∣
A
1
0
1
∣
=
∣
A
2
A
+
1
0
1
∣
\left\vert\begin{matrix} A & 1\\ 0 & 1 \end{matrix} \right\vert* \left\vert\begin{matrix} A & 1\\ 0 & 1 \end{matrix} \right\vert= \left\vert\begin{matrix} A^2 & A+1\\ 0 & 1 \end{matrix} \right\vert
∣∣∣∣A011∣∣∣∣∗∣∣∣∣A011∣∣∣∣=∣∣∣∣A20A+11∣∣∣∣
如果这还不够明显,就再来一次!
∣
A
2
A
+
1
0
1
∣
∗
∣
A
1
0
1
∣
=
∣
A
3
A
2
+
A
+
1
0
1
∣
\left\vert\begin{matrix} A^2 &A+1\\ 0 & 1 \end{matrix} \right\vert* \left\vert\begin{matrix} A & 1\\ 0 & 1 \end{matrix} \right\vert= \left\vert\begin{matrix} A^3 & A^2+A+1\\ 0 & 1 \end{matrix} \right\vert
∣∣∣∣A20A+11∣∣∣∣∗∣∣∣∣A011∣∣∣∣=∣∣∣∣A30A2+A+11∣∣∣∣
就是这么神奇!右上角就是我们需要的东西!矩阵要用的话,将1换成单位矩阵即可。
以下是代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
#define ll unsigned long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
const int MAXN = 55;
const int MOD = 100000;
char s[MAXN];
int trie[MAXN][26],tot,pos[MAXN],fail[MAXN],num[MAXN];
ll a[MAXN][MAXN],f[MAXN][MAXN];
void mul(ll f[MAXN][MAXN],ll a[MAXN][MAXN]){
ll c[MAXN][MAXN];
memset(c,0,sizeof(c));
rep(i,1,tot){
rep(j,1,tot){
rep(k,1,tot){
c[i][j]=c[i][j]+f[i][k]*a[k][j];
}
}
}
memcpy(f,c,sizeof(c));
}
void mulself(ll a[MAXN][MAXN]){
ll c[MAXN][MAXN];
memset(c,0,sizeof(c));
rep(i,1,tot){
rep(j,1,tot){
rep(k,1,tot){
c[i][j]=c[i][j]+(ll)a[i][k]*a[k][j];
}
}
}
memcpy(a,c,sizeof(c));
}
void Insert(int x){
int len=strlen(s),p=1;
rep(i,0,len-1){
int ch=s[i]-'a';
if(!trie[p][ch])trie[p][ch]=++tot;
p=trie[p][ch];
}
num[p]++;
}
queue<int>q;
vector<int>v[MAXN];
void dfs(int u,int x){
int len=v[u].size();
if(x==1)num[u]=1;
rep(i,0,len-1){
int y=v[u][i];
if(num[u])dfs(y,1);
else dfs(y,x);
}
}
int main()
{
int m,n;
while(cin>>m>>n){
tot=1;
memset(trie,0,sizeof(trie));
memset(num,0,sizeof(num));
rep(i,1,m){
scanf("%s",s);
Insert(i);
}
rep(i,0,tot)v[i].clear();
rep(i,0,25)trie[0][i]=1;
q.push(1);
while(!q.empty()){
int u=q.front();
q.pop();
rep(i,0,25){
if(trie[u][i]){
fail[trie[u][i]]=trie[fail[u]][i];
q.push(trie[u][i]);
}
else{
trie[u][i]=trie[fail[u]][i];
}
}
}
rep(i,2,tot)v[fail[i]].push_back(i);
dfs(1,0);
memset(a,0,sizeof(a));
rep(i,1,tot){
if(num[i])continue;
rep(j,0,25){
int p=trie[i][j];
if(num[p])continue;
a[i][p]++;
}
}
rep(i,1,tot){
rep(j,1,tot)f[i][j]=a[i][j];
f[i][i+tot]=a[i][i+tot]=1;
}
rep(i,tot+1,2*tot){
rep(j,1,tot)f[i][j]=a[i][j]=0;
f[i][i]=a[i][i]=1;
}
tot*=2;
ll temp=26,anss=0;
rep(i,1,n){
anss+=temp;
temp*=26;
}
int x=n;
n--;
for(;n;n>>=1){
if(n&1)mul(f,a);
mulself(a);
}
ll ans=0;
rep(i,1,tot){
ans+=f[1][i];
}
tot=2;
f[1][1]=a[1][1]=26;
f[1][2]=a[1][2]=1;
f[2][1]=a[2][1]=0;
f[2][2]=a[2][2]=1;
n=x;
n--;
for(;n;n>>=1){
if(n&1)mul(f,a);
mulself(a);
}
anss=0;
rep(i,1,tot)anss+=f[1][i];
anss-=ans;
cout<<anss<<endl;
}
return 0;
}