题意
求长度为m且包含1-n个子串的种类数.
思路
首先计算 26 + 2 6 2 + . . . . + 2 6 m 26+26^2+....+26^m 26+262+....+26m,构造矩阵为
[ s u m ( m + 1 ) 1 ] = [ s u m ( m ) ( 初 始 s u m ( 1 ) = 26 ) 1 ] ∗ [ 26 0 26 1 ] \left[ \begin{matrix} sum(m+1) & 1 \end{matrix} \right]= \left[ \begin{matrix} sum(m)(初始sum(1)=26) & 1 \end{matrix} \right] * \left[ \begin{matrix} 26 & 0 \\ 26 & 1 \end{matrix} \right] [sum(m+1)1]=[sum(m)(初始sum(1)=26)1]∗[262601]
最后实求矩阵的m次方之和,就是在矩阵多开一列,最后一列全为0,如下就可求得矩阵第一列之和.(貌似是这样,欢迎指错).还有就是l< 2 31 2^{31} 231,所以不能算到l+1次幂,算到l次幂就行了.
[ A m + 1 s u m ( A m ) + 1 0 1 ] = [ A 1 0 1 ] m + 1 \left[ \begin{matrix} A^{m+1} & sum(A^{m})+1 \\ 0 &1 \end{matrix} \right]= \left[ \begin{matrix} A & 1 \\ 0 & 1 \end{matrix} \right]^{m+1} [Am+10sum(Am)+11]=[A011]m+1
最后把第一行全加起来减去1就是了不包含任何一个给定串的答案,再用总的结果减去不包含的就是包含的了.
代码
#include<cstring>
#include<algorithm>
#include<queue>
#include<cstdio>
#include<iostream>
using namespace std;
typedef unsigned long long ll;
int tot;
const int mod=100000;
int _size;
struct Matix{
ll m[110][110];
Matix(){
memset(m,0,sizeof(m));
}
Matix operator*(const Matix &m2){
Matix t;
for(int i=0;i<_size;++i)
for(int j=0;j<_size;++j)
for(int k=0;k<_size;++k)
t.m[i][j]=(t.m[i][j]+m[i][k]*m2.m[k][j]);
return t;
};
Matix operator^(ll k) {
Matix x=*this,ans;
ans.m[0][0]=ans.m[1][1]=1;
while(k) {
if(k&1)
ans=ans*x;
x=x*x;
k>>=1;
}
return ans;
}
}g,res;
struct Trie{
int next[105010][30],fail[105010];
bool end[105010];
int root,L;
int idx(char s){
return s-'a';
}
int newnode(){
for(int i=0;i<26;i++) next[L][i]=-1;
end[L++]=0;
return L-1;
}
void init(){
L=0;
root=newnode();
}
void insert(char buf[]){
int len=strlen(buf);
int now=root;
for(int i=0;i<len;i++){
int x=idx(buf[i]);
if(next[now][x]==-1)
next[now][x]=newnode();
now=next[now][x];
}
end[now]=1;
}
void build(){
queue<int> Q;
fail[root]=root;
for(int i=0;i<26;i++){
if(next[root][i]==-1)
next[root][i]=root;
else {
fail[next[root][i]]=root;
Q.push(next[root][i]);
}
}
while(!Q.empty()){
int now=Q.front();
if(end[fail[now]]) end[now]=1;
Q.pop();
for(int i=0;i<26;i++){
if(next[now][i]==-1)
next[now][i]=next[fail[now]][i];
else {
fail[next[now][i]]=next[fail[now]][i];
Q.push(next[now][i]);
}
}
}
tot=L;
for(int i=0;i<L;i++){
if(end[i]) continue;
for(int j=0;j<26;j++){
if(end[next[i][j]]) continue;
else g.m[i][next[i][j]]++;
}
}
}
} ac;
char buf[1000010];
int main(){
// printf("%lld\n",0ll+26+26*26+26*26*26);
int n,m;
while(~scanf("%d%d",&n,&m)){
int _m=m-1;
_size=2;
res.m[0][0]=26;res.m[0][1]=1;
g.m[0][0]=26,g.m[0][1]=0,g.m[1][0]=26,g.m[1][1]=1;
// printf("----------------------\n");
// for(int i=0;i<_size;i++){
// for(int j=0;j<_size;j++)
// printf("%d ",res.m[i][j]);
// puts("");
// }
// printf("----------------------\n");
// for(int i=0;i<_size;i++){
// for(int j=0;j<_size;j++)
// printf("%d ",g.m[i][j]);
// puts("");
// }
// printf("----------------------\n");
while(_m){
if(_m&1) res=res*g;
g=g*g;
_m>>=1;
}
ll ans1=res.m[0][0];
for(int i=0;i<_size;i++)
for(int j=0;j<_size;j++)
res.m[i][j]=0,g.m[i][j]=0;
// cout<<"ans1="<<ans1<<endl;
ac.init();
for(int i=1;i<=n;i++){
scanf("%s",buf);
ac.insert(buf);
}
ac.build();
_size=tot+1;
for(int i=0;i<=tot;i++)
res.m[i][i]=1,g.m[i][tot]=1;
// printf("----------------------\n");
// for(int i=0;i<_size;i++){
// for(int j=0;j<_size;j++)
// printf("%d ",res.m[i][j]);
// puts("");
// }
// printf("----------------------\n");
// for(int i=0;i<_size;i++){
// for(int j=0;j<_size;j++)
// printf("%d ",g.m[i][j]);
// puts("");
// }
// printf("----------------------\n");
while(m){
if(m&1) res=res*g;
g=g*g;
m>>=1;
}
ll ans2=-1;
for(int i=0;i<=_size;i++){
ans2+=res.m[0][i];
}
printf("%llu\n",ans1-ans2);
}
// system("pause");
return 0;
}