2020年3月2日の検査サブAC +ガウスの消去オートマトン

かなり疑問の神々。

まず出て構築された\(AC \)上記検討し、自動機を\(DP \) 集合\(F [i]のを\) ACオートマトンである\(I \)はるかに長いエンド・ノードに期待しています。

場合\(I \)は、文字列の末尾である([I] = 0 F \ \)

否则\(\ displaystyle F [I] = 1 + \ FRAC {F [TR [I] [J]]}、{26} \)

ガウスの消去法とライン上の方程式の解。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define LL long long
using namespace std;
int T, n, len, tot = 1;
const int mod = 1e9 + 7, N = 205;
int ch[N][27], fail[N], isend[N], f[N][N];
char s[15];
LL ksm(LL a, LL b, LL mod)
{
	LL res = 1;
	for (; b; b >>= 1, a = a * a % mod)
		if (b & 1)res = res * a % mod;
	return res;
}
const int inv26 = ksm(26, mod - 2, mod);
void Insert()//AC自动机插入
{
	int now = 1, c;
	for (int i = 1; i <= len; ++i)
	{
		c = s[i] - 'a' + 1;
		if (!ch[now][c])ch[now][c] = ++tot;
		now = ch[now][c];
	}
	isend[now] = 1;
}
void build()
{
	int x; queue<int>q;
	fail[1] = 1;
	for (int i = 1; i <= 26; ++i)
	{
		if (ch[1][i])q.push(ch[1][i]), fail[ch[1][i]] = 1;
		else ch[1][i] = 1;
	}
	while (!q.empty())
	{
		x = q.front(); q.pop();
		for (int i = 1; i <= 26; ++i)
		{
			if (ch[x][i])fail[ch[x][i]] = ch[fail[x]][i], q.push(ch[x][i]);
			else ch[x][i] = ch[fail[x]][i];
		}
	}//上面是建fail指针
	for (int i = 1; i <= tot; ++i)
	{
		f[i][i] = 1;
		if (isend[i])continue;
		f[i][0] = 1;
		for (int j = 1; j <= 26; ++j)(f[i][ch[i][j]] += mod - inv26) %= mod;
	}//建方程,注意0是等号左边,1~n是等号右边
}
void work()//高斯消元基本操作
{
	for (int i = 1; i <= tot; ++i)
	{
		for (int j = i + 1; j <= tot; ++j)
			if (!f[i][i] && f[j][i])swap(f[i], f[j]);
		if (!f[i][i])continue;
		int k = ksm(f[i][i], mod - 2, mod);
		for (int j = 0; j <= tot; ++j)f[i][j] = (LL)f[i][j] * k % mod;
		for (int j = 1; j <= tot; ++j)
		{
			if (j == i)continue;
			int k = f[j][i];
			for (int t = 0; t <= tot; ++t)((f[j][t] -= (LL)k * f[i][t] % mod) += mod) %= mod;
		}
	}
}
int main()
{
	cin >> T;
	while (T--)
	{
		memset(ch, 0, sizeof(ch)); memset(fail, 0, sizeof(fail)); memset(isend, 0, sizeof(isend)); memset(f, 0, sizeof(f));
		tot = 1;
		scanf("%d", &n);
		for (int i = 1; i <= n; ++i)
		{
			scanf("%s", s + 1); len = strlen(s + 1);
			Insert();
		}
		build(); work();
		printf("%lld\n", (LL)f[1][0]*ksm(f[1][1], mod - 2, mod) % mod);//高斯消元求解
	}
	return 0;
}

おすすめ

転載: www.cnblogs.com/wljss/p/12662730.html