标签:
给出n个模板串(n<6)求出长度为不超过l(l<2^31)的单词至少包含n个字串中的一个的种类数,对2^64取模。
首先有多个模板串,考虑Aho-Corasick,然后l数据范围提示要用log级别的算法,Trie中最常见的就是矩阵,那么接着分析,问出不超过l至少包含1个,那么我们把问题简化,我们会求出长度为l的不包含任意一个情况吧,不会的同学,传送过去,就用26^l-A^l,就得到长度为l包含至少一个的个数,那么就可以得到总体的算法,26^1+26^2+26^3+26^4+......26^l-(A^1+A^2+A^3+A^4+......A^l),矩阵的幂求和可以这样:
|A,1|^(n+1) = |A^(n+1),1+A^1+A^2+A^3+A^4+......A^l|
|0,1| |0 , 1|
26^1+26^2+26^3+26^4+......26^l = 26*(1-26^l)/(1-26)
#include <cstdio> #include <iostream> #include <cstring> #include <queue> #include <cmath> #include <cstdlib> #include <algorithm> #define LL unsigned long long using namespace std; const int N = 40; const int alp = 26; struct node{ int id; bool flag; node *ch[alp],*fail; void init(){ fail = NULL; for(int i = 0;i < alp;++i)ch[i] = NULL; } }trie[N]; char s[250]; int m,ncnt; LL l; struct Matrix{ LL map[2*N][2*N]; void clear(){ memset(map,0,sizeof(map)); } }c; node *Newnode(){ node *p = &trie[ncnt]; p->init(); p->id = ncnt++; return p; } void insert(node *root,char *s){ node *p = root; while(*s != ‘\0‘){ if(!p->ch[*s-‘a‘])p->ch[*s-‘a‘] = Newnode(); p = p->ch[*s-‘a‘]; ++s; } p->flag = true; } void _build(node *root){ memset(c.map,0,sizeof(c.map)); queue <node *> q; q.push(root); while(!q.empty()){ node *p = q.front();q.pop(); for(int i = 0;i < alp;++i){ if(p->ch[i]){ node *next = p->fail; while(next && !next->ch[i])next = next->fail; p->ch[i]->fail = next ? next->ch[i]:root; if(p->ch[i]->fail->flag)p->ch[i]->flag = true; q.push(p->ch[i]); } else p->ch[i] = (p==root) ? root:p->fail->ch[i]; if(!p->ch[i]->flag)++c.map[p->id][p->ch[i]->id]; } } } Matrix Mul(Matrix x,Matrix y){ Matrix res; for(int i = 0;i < 2*ncnt;++i){ for(int j = 0;j < 2*ncnt;++j){ res.map[i][j] = 0; for(int k = 0;k < 2*ncnt;++k){ res.map[i][j] = (res.map[i][j]+y.map[k][j]*x.map[i][k]); } } } return res; } Matrix Pow(Matrix x,LL n){ Matrix res; res.clear(); for(int i = 0;i < 2*ncnt;++i)res.map[i][i] = 1; while(n){ if(n&1)res = Mul(res,x); x = Mul(x,x); n >>=1; } return res; } Matrix Sum(Matrix x,LL l){ Matrix ret; for(int i = 0;i < ncnt;++i){ for(int j = 0;j < ncnt;++j){ ret.map[i][j] = c.map[i][j]; } } for(int i = 0;i < ncnt;++i){ for(int j = ncnt;j < 2*ncnt;++j){ ret.map[i][j] = ( i == (j-ncnt)); } } for(int i = ncnt;i < 2*ncnt;++i){ for(int j = 0;j < ncnt;++j){ ret.map[i][j] = 0; } } for(int i = ncnt;i < 2*ncnt;++i){ for(int j = ncnt;j < 2*ncnt;++j){ ret.map[i][j] = ( (i-ncnt) == (j-ncnt)); } } ret = Pow(ret,l+1);//l+1可能要爆Int return ret; } LL fastp(int x,int n){ LL res = 1; LL f = (LL)x; while(n){ if(n&1)res = res*f; f = f*f; n >>= 1; } return res; } void _pre(){ for(int i = 0;i < ncnt;++i){ if(trie[i].flag){ for(int k = 0;k < ncnt;++k)c.map[i][k] = 0; for(int k = 0;k < ncnt;++k)c.map[k][i] = 0; } } } int main(){ while(scanf("%d%I64u",&m,&l) != EOF){ ncnt = 0; memset(trie,0,sizeof(trie)); node *root = Newnode(); for(int i = 0;i < m;++i){ scanf("%s",s); insert(root,s); } _build(root); LL ans = 0; _pre(); Matrix res = Sum(c,l); for(int i = ncnt;i < 2*ncnt;++i){ ans += res.map[0][i]; } ans -= 1; ans = (LL)26*(fastp(26,l)-1)*10330176681277348905LL-ans; //10330176681277348905LL是(x/25)%2^64的x的逆元 cout<<ans<<endl; } return 0; }
hdu 2243 (Aho-Corasick & 矩阵优化幂求和) - xgtao -
标签:
原文地址:http://www.cnblogs.com/xgtao984/p/5701648.html