Processing math: 100%

1. 题目

传送门= ̄ω ̄=

题目是少见的良心中文题面,就不写大意了。

2. 题解

母函数模板题耶 QvQ

ai表示价值为 i的单词的个数。

构造母函数:

G(x)=a1x+a2x2+a3x3+

对于价值为 i个字符,设它有 p个,则对于它来说母函数为:

Gi(x)=1+xi+x2i++xpi

对于用字符 i和字符 j能组合出来的情况的母函数我们可以想一下:

Gi(x)中的 a[i]pxpGj(x)中的 a[j]qxq可以合并得到新的母函数的 (a[i]pa[j]q)xp+q(其中 a[i]j表示 Gi(x)j次项的系数)

说的比较拗口。。。

打个比方吧,比如你有 2种方法得到价值 5,有 3种方法得到价值 7,那么你得到价值 (5+7=12)的方法数应当加上 (2×3=6)

不难发现就是:

G(x)=Gi(x)Gj(x)

i,j两种价值的字符组合出来的母函数 G(x)Gi(x)Gj(x)的卷积。

那么最终情况的母函数:

G(x)=G1(x)G2(x)G3(x)G26(x)

求卷积可以用 FFT 把 N2优化到 Nlog2N,但是这题多项式长度只有 51,你 FFT 快不到哪里去,说不定常数大还慢些。。。

代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

template <typename _Tp> inline void IN(_Tp& dig)
{
    char c; bool flag = 0; dig = 0;
    while (c = getchar(), !isdigit(c)) if (c == '-') flag = 1;
    while (isdigit(c)) dig = dig * 10 + c - '0', c = getchar();
    if (flag) dig = -dig;
}

struct poly
{
    LL v[55];
    LL& operator [] (const int a) {return v[a];}
    void operator *= (poly& oth)
    {
        LL tmp[55]; memset(tmp, 0, sizeof(tmp));
        for (int i = 0; i <= 50; i += 1)
            for (int j = 0; i + j <= 50; j += 1)
                tmp[i + j] += v[i] * oth[j];
        memmove(v, tmp, sizeof(v));
    }
} sum, cur;

int T, x;

LL ans;

int main(int argc, char const* argv[])
{
    IN(T);
    while (T--)
    {
        memset(sum.v, 0, sizeof(sum.v)), sum[0] = 1;
        for (int i = 1; i <= 26; i += 1)
        {
            IN(x), memset(cur.v, 0, sizeof(cur.v));
            for (int p = 0, j = 0; p <= x && j <= 50; p += 1, j += i) cur[j] = 1;
            sum *= cur;
        }
        ans = 0; for (int i = 1; i <= 50; i += 1) ans += sum[i];
        printf("%lld\n", ans);
    }
    return 0;
}
C++
分类: 文章

XZYQvQ

炒鸡辣鸡的制杖蒟蒻一枚QvQ

0 条评论

发表回复

Avatar placeholder

您的邮箱地址不会被公开。 必填项已用 * 标注