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\n", ans % mo);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/jz929/p/12210329.html
今日推荐