HDU 2243 考研路茫茫——單詞情結 AC自動機 加 矩陣乘法

  題目網址: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;
}

發佈了72 篇原創文章 · 獲贊 1 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章