HDU 2243 考研路茫茫——单词情结 AC自动机 加 矩阵乘法
2015-04-24 21:59
501 查看
题目网址:http://acm.hdu.edu.cn/showproblem.php?pid=2243 这题用的是AC自动机加矩阵乘法去做的。首先根据给的词根建立字典树,然后建立AC自动机,利用fail指针去构造矩阵。矩阵的意思是不包含词根的状态,而把矩阵0行0到sizes-1列的值相加,就是单词长度为一时,不包含词根的情况有多少种。用最大数去减,就是单词长度为一时,包含词根的种数。同样的,矩阵相乘后,乘了N次,用最大数去减,便是长度为N的单词长度包含词根的情况,把1到N的种类相加便是答案。注意,在这里的代码中,我直接把矩阵N阶的和表示了出来,所以直接减就是答案。这里求矩阵N阶的和用的是二分法,不然会超时,假设N是一阶矩阵,N^4 = N^1 + N^2 + N^2 * (N^1 + N^2).二分法中为奇数时特殊处理。
#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <math.h> #include <queue> #define maxc 35 #define maxn 26 #define mem(a) memset(a, 0, sizeof(a)) using namespace std; int tree[maxc][maxn], fails[maxc], words[6], sizes; unsigned __int64 maps[maxc][maxc], ress[maxc][maxc], tmps[maxc][maxc], tmpss[maxc][maxc], danwei[maxc][maxc], ans, rs, rss; bool num[maxc]; char ch[6]; void inits() { sizes = 1; num[0] = 0; mem(tree[0]); mem(maps); mem(ress); mem(tmps); return; } void build() { int i, a, b = 0; for(i = 1;i <= words[0];i++) { a = words[i]; if(!tree[b][a]) { mem(tree[sizes]); num[sizes] = 0; tree[b][a] = sizes++; } b = tree[b][a]; } num[b] = 1; return; } void ac_machine_build() { int i, a, b; queue<int> q; fails[0] = 0; for(i = 0;i < maxn;i++) { a = tree[0][i]; if(a) { fails[a] = 0; q.push(a); } } while(!q.empty()) { b = q.front(); q.pop(); if(num[fails[b]]) num[b] = 1; for(i = 0;i < maxn;i++) { a = tree[b][i]; if(!a) { tree[b][i] = tree[fails[b]][i]; continue; } q.push(a); fails[a] = tree[fails[b]][i]; } } return; } void zh(char *word) { int i, len; len = strlen(word); words[0] = len; for(i = 0;i < len;i++) words[i + 1] = ch[i] - 'a'; return; } void mps() { int i, j; mem(maps); for(i = 0;i < sizes;i++) { for(j = 0;j < maxn;j++) { if(!num[i]&&!num[tree[i][j]]) maps[i][tree[i][j]]++; } } return; } void mp_add(unsigned __int64 a[][maxc], unsigned __int64 b[][maxc]) { int i, j; for(i = 0;i < sizes;i++) { for(j = 0;j < sizes;j++) { a[i][j] = a[i][j] + b[i][j]; } } return; } void mp_sub(unsigned __int64 a[][maxc], unsigned __int64 b[][maxc]) { int i, j; for(i = 0;i < sizes;i++) { for(j = 0;j < sizes;j++) { a[i][j] = a[i][j] - b[i][j]; } } return; } void mp_mt(unsigned __int64 a[][maxc], unsigned __int64 b[][maxc], unsigned __int64 c[][maxc]) { int i, j, k; for(i = 0;i < sizes;i++) { for(j = 0;j < sizes;j++) { c[i][j] = 0; for(k = 0;k < sizes;k++) { c[i][j] += (a[i][k] * b[k][j]); } } } return; } void mp_fz(unsigned __int64 a[][maxc], unsigned __int64 b[][maxc]) { int i, j; for(i = 0;i < sizes;i++) { for(j = 0;j < sizes;j++) { a[i][j] = b[i][j]; } } return; } void mp_swap(unsigned __int64 a[][maxc], unsigned __int64 b[][maxc]) { int i, j; unsigned long long c[maxc][maxc]; for(i = 0;i < sizes;i++) { for(j = 0;j < sizes;j++) { c[i][j] = a[i][j]; } } for(i = 0;i < sizes;i++) { for(j = 0;j < sizes;j++) { a[i][j] = b[i][j]; } } for(i = 0;i < sizes;i++) { for(j = 0;j < sizes;j++) { b[i][j] = c[i][j]; } } return; } void res(unsigned __int64 n) { if(n == 1) { int i, j; for(i = 0;i < sizes;i++) { for(j = 0;j < sizes;j++) { tmpss[i][j] = ress[i][j] = maps[i][j]; } } rs = rss = 26; return; } res(n / 2); rs = rs * rss + rs; rss = rss * rss; unsigned __int64 tp[maxc][maxc]; mp_mt(ress, tmpss, tp); mp_add(ress, tp); mp_mt(tmpss, tmpss, tmps); if(n % 2) { rs = (rs + 1) * 26; rss *= 26; mp_add(ress, danwei); mp_mt(ress, maps, tp); mp_fz(ress, tp); mp_mt(tmps, maps, tmpss); } else { mp_swap(tmps, tmpss); } } int main() { int i, n; unsigned __int64 m, tmp; for(i = 0;i < 35;i++) { danwei[i][i] = 1; } while(scanf("%d%I64u", &n, &m) != EOF) { inits(); ans = 0; for(i = 0;i < n;i++) { mem(ch); scanf("%s", ch); zh(ch); build(); } ac_machine_build(); mps(); res(m); for(i = 0;i < sizes;i++) ans += ress[0][i]; printf("%I64u\n", rs - ans); } return 0; }
相关文章推荐
- HDU 2243 考研路茫茫――单词情结 (AC自动机 + 矩阵快速幂)
- HDU 2243 考研路茫茫——单词情结 (AC自动机 + 矩阵快速幂)
- poj -- 2778 DNA Sequence && hdu -- 2243 考研路茫茫——单词情结(AC自动机 + 矩阵)
- 考研路茫茫——单词情结 HDU - 2243 AC自动机/特征字符串构造计数/等比矩阵求和
- HDU 2243 考研路茫茫——单词情结 AC自动机 + 矩阵快速幂
- 【hdu2243】【AC自动机】【矩阵乘法】考研路茫茫——单词情结
- hdoj 2243 考研路茫茫——单词情结 【AC自动机 + 构造矩阵】
- AC自动机专题——P - 考研路茫茫――单词情结 HDU - 2243 矩阵快速幂+AC自动机
- hdu 2243 考研路茫茫——单词情结(AC自动+矩阵)
- 【AC自动机】【矩阵乘法】【等比数列】hdu2243 考研路茫茫——单词情结
- HDU 2243 考研路茫茫——单词情结 求长度小于等于L的通路总数的方法
- 考研路茫茫--单词情结 - HDU 2243(AC自动机+矩阵乘法)
- HDU 2243 考研路茫茫——单词情结
- HDU 2243 考研路茫茫——单词情结(AC自动机+矩阵快速幂)
- hdu 2243考研路茫茫——单词情结—解题报告
- HDU 2243 考研路茫茫——单词情结(AC自动机+DP+快速幂)
- hdu 2243 考研路茫茫——单词情结
- HDU-2243 考研路茫茫——单词情结(AC自动机)
- hdu 2243考研路茫茫——单词情结—解题报告
- Hdu 2243 考研路茫茫——单词情结 (AC自动机+矩阵)