• hud2243 考研路茫茫——单词情结


    考研路茫茫——单词情结

    Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)

    Problem Description

    背单词,始终是复习英语的重要环节。在荒废了3年大学生涯后,Lele也终于要开始背单词了。
    一天,Lele在某本单词书上看到了一个根据词根来背单词的方法。比如"ab",放在单词前一般表示"相反,变坏,离去"等。

    于是Lele想,如果背了N个词根,那这些词根到底会不会在单词里出现呢。更确切的描述是:长度不超过L,只由小写字母组成的,至少包含一个词根的单词,一共可能有多少个呢?这里就不考虑单词是否有实际意义。

    比如一共有2个词根 aa 和 ab ,则可能存在104个长度不超过3的单词,分别为
    (2个) aa,ab,
    (26个)aaa,aab,aac...aaz,
    (26个)aba,abb,abc...abz,
    (25个)baa,caa,daa...zaa,
    (25个)bab,cab,dab...zab。

    这个只是很小的情况。而对于其他复杂点的情况,Lele实在是数不出来了,现在就请你帮帮他。

    Input

    本题目包含多组数据,请处理到文件结束。
    每组数据占两行。
    第一行有两个正整数N和L。(0<N<6,0<L<2^31)
    第二行有N个词根,每个词根仅由小写字母组成,长度不超过5。两个词根中间用一个空格分隔开。

    Output

    对于每组数据,请在一行里输出一共可能的单词数目。
    由于结果可能非常巨大,你只需要输出单词总数模2^64的值。

    Sample Input

    2 3
    aa ab
    1 2
    a

    Sample Output

    104
    52





    ac自动机上dp。。。我们才用反向思考,求出没有出现的个数。
    dp[i][j] 表示节点 i ,走了 j 步,没有出现的个数。
    用矩阵优化 j 这一维就好啦~
    但是我们要求了是j 1~L 的前缀和。
    所以还有一个矩阵

    [left[egin{matrix} a 1\ 0 1 \ end{matrix} ight] ]

    这个就是求前缀和。。。如果是矩阵前缀和就把a换成矩阵,1换成等大小的单位矩阵就好了。



    
    #include<bits/stdc++.h>
    #define LL unsigned long long
    using namespace std;
    const int maxn = 120;
    struct lpl{
    	int n, m; 
    	LL a[maxn][maxn];
    }op, bas, ini;
    struct ld{int son[30]; int fail; bool f;}node[maxn];
    bool vis[30];
    int N, L, cnt;
    LL all, ans;
    char s[maxn];
    
    
    inline lpl operator * (lpl &A, lpl &B){
    	lpl ret; ret.n = A.n; ret.m = B.m;
    	for(int i = 1; i <= ret.n; ++i)
    		for(int j = 1; j <= ret.m; ++j){
    			ret.a[i][j] = 0;
    			for(int k = 1; k <= ret.n; ++k) ret.a[i][j] += A.a[i][k] * B.a[k][j];
    		}
    	return ret;
    }
    
    inline lpl Fpow(lpl A, int t){
    	lpl ret; lpl tmp = A; ret.n = ret.m = A.n; 
    	memset(ret.a, 0, sizeof(ret.a)); memset(ini.a, 0, sizeof(ini.a));
    	for(int i = 1; i <= ret.n; ++i) ret.a[i][i] = 1;
    	while(t){ 
    		if(t & 1) ret = ret * tmp;
    		tmp = tmp * tmp; t >>= 1;
    	}
    	return ret;
    }
    
    inline void putit(){
    	int len, qwe, now; cnt = 1; memset(node, 0, sizeof(node));
    	for(int i = 1; i <= N; ++i){
    		scanf("%s", s + 1); len = strlen(s + 1); now = 1;
    		for(int j = 1; j <= len; ++j){
    			qwe = s[j] - 'a' + 1;
    			if(!node[now].son[qwe]) node[now].son[qwe] = ++cnt;
    			now = node[now].son[qwe]; if(j == len) node[now].f = true;
    		}
    	}
    	lpl lin; lin.n = lin.m = 2; memset(lin.a, 0, sizeof(lin.a));
    	lin.a[1][1] = 26; lin.a[1][2] = lin.a[2][2] = 1;
    	lin = Fpow(lin, L); all = lin.a[1][1] + lin.a[1][2] - 1;
    }
    
    inline void AC(){
    	queue<int> q; queue<int> qqq;
    	q.push(1); qqq.push(1);
    	while(!q.empty()){
    		int now = q.front(); q.pop();
    		for(int i = 1; i <= 26; ++i){
    			if(!node[now].son[i]) continue;
    			q.push(node[now].son[i]); qqq.push(node[now].son[i]);
    			if(now == 1){node[node[now].son[i]].fail = 1; continue;}
    			int t = node[now].fail;
    			while(!node[t].son[i] && t) t = node[t].fail;
    			if(!t) node[node[now].son[i]].fail = 1;
    			else node[node[now].son[i]].fail = node[t].son[i];
    		}
    	}
    	while(!qqq.empty()){
    		int now = qqq.front(); qqq.pop();
    		int qwe = now;
    		while(qwe){
    			if(node[qwe].f){node[now].f = true; break;}
    			qwe = node[qwe].fail;
    		}
    	}
    }
    
    inline void workk(){
    	op.n = cnt, op.m = 1; memset(op.a, 0, sizeof(op.a)); op.a[1][1] = 1;
    	memset(bas.a, 0, sizeof(bas.a)); bas.n = bas.m = cnt;
    	for(int i = 1; i <= cnt; ++i){
    		int now = i, lft = 26; memset(vis, false, sizeof(vis));
    		while(now){
    			for(int j = 1; j <= 26; ++j){
    				if(!node[now].son[j]) continue;
    				if(!vis[j]){
    					vis[j] = true; lft--;
    					bas.a[node[now].son[j]][i] = 1;
    				}
    			}
    			now = node[now].fail;
    		}
    		bas.a[1][i] = lft;
    	}
    	for(int i = 1; i <= cnt; ++i)
    		if(node[i].f)
    			for(int j = 1; j <= cnt; ++j) bas.a[i][j] = 0;	
    	ini.n = ini.m = cnt * 2;
    	for(int i = 1; i <= cnt; ++i){
    			ini.a[i][i + cnt] = ini.a[i + cnt][i + cnt] = 1;	
    		for(int j = 1; j <= cnt; ++j) ini.a[i][j] = bas.a[i][j];	
    	}	
    	ini = Fpow(ini, L);
    	for(int i = 1; i <= cnt; ++i)
    		for(int j = 1; j <= cnt; ++j){
    			bas.a[i][j] = ini.a[i][j] + ini.a[i][j + cnt];
    			if(i == j) bas.a[i][j]--;
    		}
    	op = bas * op; ans = 0;
    	for(int i = 1; i <= cnt; ++i) ans += op.a[i][1];
    	ans = all - ans;
    	cout << ans << endl;
    }
    
    int main()
    {
    	while(~scanf("%d%d", &N, &L)){
    		putit();
    		AC();
    		workk();
    	}
    	return 0;
    }
    
    
    心如花木,向阳而生。
  • 相关阅读:
    curl: (1) Protocol 'http not supported or disabled in libcurl
    线程-分为两类-用户线程和守护线程
    laypage分页插件的使用
    uploadify上传图片插件的使用
    redis安装
    php连接测试memcached
    pageY、clientY、screenY、offsetY的区别
    audio和video样式兼容
    实现剪切和复制功能
    滚动条样式
  • 原文地址:https://www.cnblogs.com/LLppdd/p/9677888.html
Copyright © 2020-2023  润新知