zoukankan      html  css  js  c++  java
  • HDU 2243 考研路茫茫——单词情结 (AhoCorasick & 矩阵优化幂求和) xgtao

    考研路茫茫——单词情结

    给出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;
    }
    

      

                                              

                                                

  • 相关阅读:
    svn上传文件钩子
    linux服务器版svn安装
    csp-s模拟55
    csp-s模拟54
    csp-s模拟53
    csp-s模拟52
    csp-s模拟51
    csp-s模拟50
    csp-s模拟49
    csp-s模拟48
  • 原文地址:https://www.cnblogs.com/xgtao984/p/5701648.html
Copyright © 2011-2022 走看看