链接:http://acm.hdu.edu.cn/showproblem.php?pid=2243
题意:给定N(1<= N < 6)个长度不超过5的词根,问长度不超过L(L <231)的单词中至少含有一个词根的单词个数;结果mod 264.
基础:poj 2778DNA 序列求的是给定长度不含模式串的合法串的个数;串长度相当,都到了int上界了;
1.mod 264直接使用unsigned long long自然溢出即可;说的有些含蓄。。并且也容易想到是直接使用内置类型,要不然高精度的mod 2^64要跪;
2.本题是poj 2778的升级版,里面求的是范围内,并不是特定的长度,并且还是含有至少一个;那么直接从反面求解,即用总个数-不含有词根的个数;
3.对矩阵的操作,实现对连续离散指数求和; 对矩阵增加一列,全部为1,增加的行除了右下角为1外,其他均为0;
$\begin{pmatrix}
A\Rightarrow \begin{pmatrix}
A & 1\\
0 & 1
\end{pmatrix}
\end{pmatrix}$
$ans = \sum \limits_{i=0}^{\rm size}mat\left [ 0 \right ]\left [ i \right ]$
同理求解:$\sum \limits_{i=0}^{\rm size}26^i$只需建立二维矩阵
\begin{vmatrix}
26 & 1\\
0 & 1
\end{vmatrix}之后直接矩阵快速幂即可;
// 15ms 1632k
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<vector>
#include<cmath>
#include<stdlib.h>
#include<time.h>
#include<stack>
#include<set>
#include<map>
#include<queue>
using namespace std;
#define rep0(i,l,r) for(int i = (l);i < (r);i++)
#define rep1(i,l,r) for(int i = (l);i <= (r);i++)
#define rep_0(i,r,l) for(int i = (r);i > (l);i--)
#define rep_1(i,r,l) for(int i = (r);i >= (l);i--)
#define MS0(a) memset(a,0,sizeof(a))
#define MS1(a) memset(a,-1,sizeof(a))
#define MSi(a) memset(a,0x3f,sizeof(a))
#define inf 0x3f3f3f3f
#define lson l, m, rt << 1
#define rson m+1, r, rt << 1|1
#define sqr(a) (a)*(a)
typedef pair<int,int> PII;
#define A first
#define B second
#define MK make_pair
typedef __int64 ll;
typedef unsigned long long ull;
template<typename T>
void read1(T &m)
{
T x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
m = x*f;
}
template<typename T>
void read2(T &a,T &b){read1(a);read1(b);}
template<typename T>
void read3(T &a,T &b,T &c){read1(a);read1(b);read1(c);}
template<typename T>
void out(T a)
{
if(a>) out(a/);
putchar(a%+'');
}
int T,kase = ,i,j,k,n,m,top;
#define mod 100000
struct Matrix{
ull d[][];
int sz;//不能也弄成ull,否则int => ull会出错
Matrix(int r){MS0(d); sz = r;}
void init(){
for(int i = ;i < sz;i++)
d[i][i] = ;
}
Matrix operator*(const Matrix& a)const{
Matrix ans(a.sz);
for(int i = ;i < sz;i++)
for(int j = ;j < sz;j++){
for(int k = ;k < sz;k++)
ans.d[i][j] += d[i][k]*a.d[k][j];
}
return ans;
}
void debug(){
rep0(i,,sz){
rep0(j,,sz) cout<<d[i][j]<<" ";
cout<<endl;
}
}
};
Matrix Pow(Matrix a,ll m)
{
Matrix ans(a.sz);
ans.init();
while(m){
if(m&) ans = ans*a;
a = a*a;
m >>= ;
}
return ans;
}
const int sigma_size = ;
const int maxn = ;
struct Aho_Corasick{
int ch[maxn][sigma_size];
int val[maxn],f[maxn],last[maxn],cnt[maxn];
int sz;
map<string,int> ms;
Aho_Corasick(){}
void init(){sz = ;val[] = ; MS0(ch[]);MS0(cnt);ms.clear();}
int idx(char c){return c-'a';}
void Insert(char *s,int v){
int u = ,n = strlen(s);
for(int i = ;i < n;i++){
int c = idx(s[i]);
if(!ch[u][c]){
MS0(ch[sz]);
val[sz] = ;
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u] = v;
}
void getFail(){
queue<int> q;
f[] = ;
for(int c = ;c < sigma_size;c++){ //初始化队列
int u = ch[][c];
if(u) { f[u] = ; q.push(u); last[u] = ;}
}
while(!q.empty()){
int r = q.front();q.pop();
for(int c = ;c < sigma_size;c++){
int u = ch[r][c];
if(!u) {ch[r][c] = ch[f[r]][c]; continue;}//实现压缩
q.push(u);
int v = f[r];
while(v && !ch[v][c]) v = f[v];
f[u] = ch[v][c];
last[u] = val[f[u]]?f[u]:last[f[u]];
}
}
}
Matrix Find(){
Matrix ans(sz+);
for(int i = ;i < sz;i++){
if(val[i] || last[i]) continue;
for(int j = ;j < sigma_size;j++){
int v = ch[i][j];
if(val[v] || last[v]) continue;
ans.d[i][v]++;
}
ans.d[i][sz] = ;//添加一列保存前面的sigma和;
}
ans.d[sz][sz] = ;//右下角
return ans;
}
}ac;
char p[];
int main()
{
ull n,L;
//freopen("data.txt","r",stdin);
while(scanf("%I64d%I64d",&n,&L) == ) {
ac.init();
rep1(i,,n){
scanf("%s",p);
ac.Insert(p,i);
}
ac.getFail();
Matrix ans = ac.Find();
ans = Pow(ans,L);
ull cnt = ;
rep0(i,,ans.sz) cnt += ans.d[][i];
Matrix a();//求总和
a.d[][] = ,a.d[][] = a.d[][] = ;
a = Pow(a,L);
printf("%I64u\n",a.d[][]+a.d[][]-cnt);
}
return ;
}