zoukankan      html  css  js  c++  java
  • HDU-2243 考研路茫茫——单词情结 AC自动机+矩阵快速幂

    题意

    给n个模式串,问有多少个长度不超过L的字符串中至少出现一种模式串。

    分析

    有多少个长度为L的字符串中不出现任意一个模式串的题已经做过,构造一个矩阵(A),答案(s_n)即为(s_0*A^n)

    用矩阵快速幂算下就行了,这题的计算方法就显然是(26^0+26^1+26^2+dots+26^n-(s_0*A^0+s_0*A^1+s_0*A^2+dots+s_0*A^n))

    这样显然会超时,考虑重新构造两个矩阵

    [left [ egin{matrix}26^n&s_nend{matrix} ight ] imes left [ egin{matrix}26&1\0&1end{matrix} ight ] =left [ egin{matrix}26^{n+1}&s_{n+1}end{matrix} ight ] ]

    设字典树一共(m)个结点,我们要构造一个((m+1) imes(m+1))的矩阵

    [left [ egin{matrix}f[n][0]&dots&f[n][m-1]&s_nend{matrix} ight ] imes left [ egin{matrix}A&1\0&1end{matrix} ight ] =left [ egin{matrix}f[n+1][0]&dots&f[n+1][m-1]&s_{n+1}end{matrix} ight ] ]

    对于取模,直接用ull自然溢出就行了。

    Code

    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define pb push_back
    #define lson l,mid,p<<1
    #define rson mid+1,r,p<<1|1
    #define ll unsigned long long
    using namespace std;
    const int inf=1e9;
    const ll mod=1e9+7;
    const int maxn=1e5+10;
    int n;
    ll L;
    char s[11];
    struct mat{
    	int n;
    	ll a[40][40];
    	mat(){
    		memset(a,0,sizeof(a));
    	}
    	mat(int _n){
    		n=_n;memset(a,0,sizeof(a));
    	}
    	mat operator *(const mat &r)const{
    		mat ret=mat(n);
    		for(int i=0;i<n;i++)
    		for(int j=0;j<n;j++)
    		for(int k=0;k<n;k++)
    		ret.a[i][j]+=a[i][k]*r.a[k][j];
    		return ret;
    	}
    };
    mat A,B=mat(2);
    mat ksm(mat a,ll b){
    	mat ret=mat(a.n);
    	for(int i=0;i<ret.n;i++) ret.a[i][i]=1;
    	while(b){
    		if(b&1) ret=ret*a;
    		b>>=1;
    		a=a*a;
    	}
    	return ret;
    }
    struct ACtree{
    	int son[maxn][26],fail[maxn],ed[maxn],tot;
    	int newnode(){
    		for(int i=0;i<26;i++) son[tot][i]=0;
    		ed[tot++]=0;
    		return tot-1;
    	}
    	void init(){
    		tot=0;newnode();
    	}
    	void ins(char s[]){
    		int rt=0,m=strlen(s);
    		for(int i=0;i<m;i++){
    			if(!son[rt][s[i]-'a']) son[rt][s[i]-'a']=newnode();
    			rt=son[rt][s[i]-'a'];
    		}
    		ed[rt]=1;
    	}
    	void gao(){
    		queue<int>q;
    		for(int i=0;i<26;i++) if(son[0][i]) fail[son[0][i]]=0,q.push(son[0][i]);
    		while(!q.empty()){
    			int u=q.front();q.pop();
    			for(int i=0;i<26;i++){
    				if(son[u][i]){
    					fail[son[u][i]]=son[fail[u]][i];
    					q.push(son[u][i]);
    				}else{
    					son[u][i]=son[fail[u]][i];
    				}
    				ed[son[u][i]]|=ed[fail[son[u][i]]];
    			}
    		}
    		A=mat(tot+1);
    		for(int i=0;i<tot;i++){
    			for(int j=0;j<26;j++){
    				if(ed[son[i][j]]) continue;
    				A.a[i][son[i][j]]++;
    			}
    		}
    		for(int i=0;i<=tot;i++) A.a[i][tot]=1;
    	}
    	ll qy(){
    		ll ans=0;
    		mat ret=ksm(B,L);
    		ans+=ret.a[0][1]+ret.a[0][0];
    		ret=ksm(A,L);
    		for(int i=0;i<=tot;i++) ans-=ret.a[0][i];
    		return ans;
    	}
    }AC;
    int main(){
    	//ios::sync_with_stdio(false);
    	//freopen("in","r",stdin);
    	B.a[0][0]=26,B.a[0][1]=B.a[1][1]=1;
    	while(~scanf("%d%llu",&n,&L)){
    		AC.init();
    		for(int i=1;i<=n;i++){
    			scanf("%s",s);
    			AC.ins(s);
    		}
    		AC.gao();
    		printf("%llu
    ",AC.qy());
    	}
    	return 0;
    }
    
  • 相关阅读:
    五星评价
    IE9以上 CSS文件因Mime类型不匹配而被忽略 其他浏览器及IE8以下显示正常
    js时间显示设置
    jq手风琴---点击时列表的左边距逐渐减小
    break continue return
    validate插件:验证密码没有空格 用户名是5-10位 至少包含数字和大小写字母中的两种字符
    Commons IO
    Servlet & JSP
    设计模式
    Table of Contents
  • 原文地址:https://www.cnblogs.com/xyq0220/p/11593462.html
Copyright © 2011-2022 走看看