HDU 2243 考研路茫茫——单词情结 AC自动机 加 矩阵乘法

来源:互联网 发布:淘宝销售法则有哪些 编辑:程序博客网 时间:2024/05/22 11:29
  题目网址: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;}

0 0
原创粉丝点击