jzoj 3857. 【NOIP2014八校联考第3场第1试10.4】反抗希碧拉系统续(regex)

这题是要玩死我的节奏啊。。。
考场打完(T1)(T3)然后只剩(30min),而且这题也没十分弄清楚题意,所以(GG)
但就算考试后知道了正解,还是有些糊涂。
到了晚上听完讲(其实只听了设个二维数组就走了,因为我感觉自己已经懂了),才渐渐弄清楚了思路,呵呵,码完即可(* ̄︶ ̄)。

由于元素的种类最多只有5个,所以我们可以联想到状压。

然后我们可以通过题目中的那些转移方式(如(表达式)+中可以从表达式最右边的元素走到最左边的元素,[元素][元素]中我们就可以从第一个元素走到第二个元素),这样我们就可以构成一个图。

(f[i][s])表示走了(i)步,当前可能到达的元素的状压状态为(s)的方案数,这种设法使为了防止计算重复的。
直接转移显然不行,所以我们需要预处理出其它的东西。
我们设(to[i][j])表示从(i)这个状态转移到(j)这个状态时都能走同一种串的方案数。
如此状态转移方程也就自然出来了:(f[i][s]=f[i-1][s']*to[s'][s])
其实这个设法是十分巧妙的。因为我们不这样设的话,就可能会有某些神奇的东东算重然后(GG)。(我之前打得时候设的不一样导致答案一直很大)

对于这个转移,我们枚举(i),以及要转移的那个相同的字符是什么,然后对于(i)中的每个元素,我们找到它所连向的包含这个字符的元素,并求出其状压状态(s),然后我们就可以将(to[i][s])(1)
解释:因为我们对于(i)(s)的路径全都是相同的,因为它们在这种情况下加的都是同一种字符,所以我们只需要对此方案数加(1)即可。而其它字符会在其它时候做掉。
我们在预处理出这个东西以后,可以发现转移可以用矩乘优化。

code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 510
#define mo 4294967296ll
#define ll long long
#define mem(x, a) memset(x, a, sizeof x)
#define mpy(x, y) memcpy(x, y, sizeof y)
#define fo(x, a, b) for (int x = (a); x <= (b); x++)
#define fd(x, a, b) for (int x = (a); x >= (b); x--)
#define go(x) for (int p = tail[x], v; p; p = e[p].fr)
using namespace std;
int n, len, ys[7][27], tot = 0;
int ke[80], cf[7], gs[7], z[7], top = 0, gt[27];
ll f[80][80], c[80][80], to[80][80], ans = 0;
char s[N];

template<typename T>
inline void read(T& x)
{
	x = 0; int f = 0; char c = getchar();
	while (c < '0' || c > '9') f = (c == '-') ? 1 : f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
	if (f == 1) x = -x;
}

ll gsc(ll x, ll y)
{
	ll s = 0;
	while (y)
	{
		if (y & 1) s = (s + x) % mo;
		x = (x + x) % mo, y >>= 1;
	}
	return s;
}

int main()
{
	freopen("regex.in", "r", stdin);
	freopen("regex.out", "w", stdout);
	scanf("%s%d", s + 1, &n);
	len = strlen(s + 1);
	cf[0] = 1; fo(i, 1, 6) cf[i] = cf[i - 1] << 1;
	fo(i, 1, len)
	{
		if (s[i] == '[')
		{
			i++, tot++, ke[tot - 1] |= cf[tot - 1];
			while (s[i] != ']') gs[tot]++, ys[tot][s[i] - 'a'] = 1, i++;
		}
		else if (s[i] == '(') z[++top] = tot + 1;
		else if (s[i] == ')') ke[tot] |= cf[z[top] - 1], top--;
	}
	fo(i, 1, cf[tot] - 1)
	{
		mem(gt, 0);
		fo(j, 1, tot)
		{
			if (! (i & cf[j - 1])) continue;
			fo(k, 1, tot)
			{
				if (! (ke[j] & cf[k - 1])) continue;
				fo(l, 0, 25) if (ys[k][l]) gt[l] |= cf[k - 1];
			}
		}
		fo(j, 0, 25) to[i][gt[j]]++;
	}
	f[1][1] = gs[1], n--;
	while (n)
	{
		if (n & 1)
		{
			mem(c, 0);
			fo(k, 1, cf[tot] - 1)
				fo(j, 1, cf[tot] - 1)
					(c[1][j] += gsc(f[1][k], to[k][j]) % mo) %= mo;
			mpy(f, c);
		}
		mem(c, 0);
		fo(k, 1, cf[tot] - 1)
			fo(i, 1, cf[tot] - 1)
				fo(j, 1, cf[tot] - 1)
					(c[i][j] += gsc(to[i][k], to[k][j]) % mo) %= mo;
		mpy(to, c);
		n >>= 1;
	}
	fo(i, 1, cf[tot] - 1)
		if (i & cf[tot - 1]) ans += f[1][i];
	printf("%lld
", ans % mo);
	return 0;
}

转载需注明出处。
原文地址:https://www.cnblogs.com/jz929/p/12210329.html