ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2022牛客暑假多校第四场C.Easy Counting Problem

2022-08-01 00:02:47  阅读:127  来源: 互联网

标签:第四场 int 多校 poly 牛客 const return mod size


C.Easy Counting Problem

感谢 Pedestrian1 的指导

题意:\(q\) 次询问,每次问在一定约束条件下构造出长度为 \(n\) 的序列的方案数,只能用 \(w\) 种数字构造,且每种数字至少使用 \(c_i\) 次

知识点:多项式,生成函数

首先知道这个是要使用EGF的相关生成函数解决,然后我们先推式子

设对于数字 \(i\) 的方案生成函数为 \(A_i(x)\) 那么设答案多项式为 \(F(x)\)

则有 \(F(x) = \prod_{i=0}^{w-1} A_i(x)\)

其中 \(A_i(x) = \sum_{j=c_i} \frac{x^i}{i!}\)

即 \(F(x) = \prod_{i=0}^{w-1} (e^x - \sum_{i=0}^{c_i-1}\frac{x^i}{i!})\)

那么对于每次询问给出的 \(n\),答案就是 \([x^n]F(x)\) ,现在问题就是如何求这个

显然,如果我们每次询问都是这么去直接卷,肯定是会超时的,那么我们考虑其他方法

考虑到 \(w\) 与后面的 \(\sum c_i\) 的范围很小,于是我们考虑展开这个式子

其中我们定义 \(f_i(x) = \sum_{i=0}^{c_i-1}\frac{x^i}{i!}\)

\(g_k(x)\) 表示 \(w\) 个 \(f\) 中选 \(k\) 个相乘的和,是用多项式来表达的(实际意义就是 \(w\) 个数任意选 \(k\) 个来组的方案数)

\(F(x) = \sum_{i=0}^{w} (-1)^i*e^{(w-i)x}*g_i(x)\)

注意到,如果我们想求 \([x^n]F(x)\) 我们可以对于每个 \(i\) 求出 \(\sum_{j=0}^n[x^j]e^{(w-i)x}*[x^{n-j}]g_i(x)\) ,然后求和即可

\(g\) 部分可以用 \(2^w\) 枚举或者 \(w^2\) 的背包求出,这里用背包写

这题感觉又卡时间又卡空间的,注意换一个比较好的板子。

#include <bits/stdc++.h>
#define endl '\n'
#define ls u << 1
#define rs u << 1 | 1
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int INF = 0x3f3f3f3f, N = 1e7 + 10;
const int MOD = 998244353;
const double eps = 1e-6;
const double PI = acos(-1);
inline int lowbit(int x) {return x & (-x);}

namespace polybase {//范围为1e9需要先取模,别忘记改模数,原根和数组长度
    constexpr ll mod = 998244353, g = 3, L = 1 << 22;

    ll fpow(ll x, ll r)
    {
        ll result = 1;
        while (r)
        {
            if (r & 1)result = result * x % mod;
            r >>= 1;
            x = x * x % mod;
        }
        return result;
    }

    int w[L], _ = []
    {
        ll x = fpow(g, (mod - 1) / L);
        w[L / 2] = 1;
        for (int i = L / 2 + 1; i < L; i++)
            w[i] = w[i - 1] * x % mod;
        for (int i = L / 2 - 1; i >= 0; i--)
            w[i] = w[i << 1];
        return 0;
    }();

    inline int norm(int n) { return 1 << __lg(n * 2 - 1); }

    void dft(ll *a, int n)
    {
        for (int k = n >> 1; k; k >>= 1)
            for (int i = 0; i < n; i += k << 1)
                for (int j = 0; j < k; j++)
                {
                    ll &x = a[i + j], y = a[i + j + k];
                    a[i + j + k] = (x - y + mod) * w[k + j] % mod;
                    x += y;
                    if (x >= mod)x -= mod;
                }
    }

    void idft(ll *a, int n)
    {
        for (int k = 1; k < n; k <<= 1)
            for (int i = 0; i < n; i += k << 1)
                for (int j = 0; j < k; j++)
                {
                    ll x = a[i + j], y = a[i + j + k] * w[k + j] % mod;
                    a[i + j + k] = x - y < 0 ? x - y + mod : x - y;
                    a[i + j] += y;
                    if (a[i + j] >= mod)a[i + j] -= mod;
                }
        for (int i = 0, inv = mod - (mod - 1) / n; i < n; i++)
            a[i] = a[i] * inv % mod;
        reverse(a + 1, a + n);
    }

    struct poly : public vector<ll>
    {
        using vector<ll>::vector;
#define T (*this)

        poly modxk(int k) const
        {
            k = min(k, (int) size());
            return poly(begin(), begin() + k);
        }

        poly rev() const { return poly(rbegin(), rend()); }

        friend void dft(poly &a) { dft(a.data(), a.size()); }

        friend void idft(poly &a) { idft(a.data(), a.size()); }

        friend poly operator*(const poly &x, const poly &y)
        {
            if (x.empty() || y.empty())return poly();
            poly a(x), b(y);
            int len = a.size() + b.size() - 1;
            int n = norm(len);
            a.resize(n), b.resize(n);
            dft(a), dft(b);
            for (int i = 0; i < n; i++)
                a[i] = a[i] * b[i] % mod;
            idft(a);
            a.resize(len);
            return a;
        }

        poly operator+(const poly &b)
        {
            poly a(T);
            if (a.size() < b.size())
                a.resize(b.size());
            for (int i = 0; i < b.size(); i++)//用b.size()防止越界
            {
                a[i] += b[i];
                if (a[i] >= mod)a[i] -= mod;
            }
            return a;
        }

        poly operator-(const poly &b)
        {
            poly a(T);
            if (a.size() < b.size())
                a.resize(b.size());
            for (int i = 0; i < b.size(); i++)
            {
                a[i] -= b[i];
                if (a[i] < 0)a[i] += mod;
            }
            return a;
        }

        poly operator*(const ll p)
        {
            poly a(T);
            for (auto &x:a)
                x = x * p % mod;
            return a;
        }

        poly &operator<<=(int r) { return insert(begin(), r, 0), T; }//注意逗号,F(x)*(x^r)

        poly operator<<(int r) const { return poly(T) <<= r; }

        poly operator>>(int r) const { return r >= size() ? poly() : poly(begin() + r, end()); }

        poly &operator>>=(int r) { return T = T >> r; }//F[x]/(x^r)

        poly deriv()//求导
        {
            if (empty())return T;
            poly a(size() - 1);
            for (int i = 1; i < size(); i++)//注意是size()
                a[i - 1] = T[i] * i % mod;
            return a;
        }

        poly integ()//积分
        {
            poly a(size() + 1);
            for (int i = 1; i < a.size(); i++)//注意是a.size()
                a[i] = T[i - 1] * fpow(i, mod - 2) % mod;
            return a;
        }

        poly inv(int n)
        {
            poly a{fpow(T[0], mod - 2)};
            int k = 1;
            while (k < n)
            {
                k <<= 1;
                a = (a * 2 - modxk(k) * a * a).modxk(k);
            }
            return a.modxk(n);
        }

        poly sqrt(int n)//f[0]必须等于1
        {
            poly a{1};
            int k = 1;
            const ll inv2 = fpow(2, mod - 2);
            while (k < n)
            {
                k <<= 1;
                a = ((modxk(k) * a.inv(k)).modxk(k) + a) * inv2;
            }
            return a.modxk(n);
        }

        poly ln(int n)//需要保证f[0]=1
        {
            return (deriv() * inv(n)).integ().modxk(n);
        }

        poly exp(int n)//需要保证f[0]=0
        {
            poly a{1};
            int k = 1;
            while (k < n)
            {
                k <<= 1;
                a = (a * (poly{1} - a.ln(k) + modxk(k))).modxk(k);
            }
            return a.modxk(n);
        }

#undef T
    };
}

using namespace polybase;
int fac[N], ifac[N];
poly G[11], F[11];
inline void solve() {
    int w; cin >> w;
    for (int i = 0; i < w; i ++ ) {
        int x; cin >> x;
        G[i].resize(x);
        for (int j = 0; j < x; j ++ ) G[i][j] = ifac[j];
    }
    F[0] = poly{1};
    for (int i = 0; i < w; i ++ ) for (int j = i + 1; j; j -- ) F[j] = F[j] + F[j - 1] * G[i];
    int m; cin >> m;
    while (m -- ) {
        int n; cin >> n;
        ll res = 0;
        for (int i = 0; i <= w; i ++ ) {
            ll now = fpow(w - i, n);
            ll nv = fpow(w - i, MOD - 2);
            for (int j = 0; j < F[i].size() && j <= n; j ++ ) {
                if (i == w && n == j) now = 1;
                res = (res + 1ll * (i & 1 ? MOD - 1 : 1) * ifac[n - j] % MOD * now % MOD * F[i][j] % MOD) % MOD;
                now = now * nv % MOD;
            }
        }
        res = res * fac[n] % MOD;
        cout << res << endl;
    }
}
signed main() {
#ifdef DEBUG
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
    auto now = clock();
#endif
    ios::sync_with_stdio(false), cin.tie(nullptr);
    cout << fixed << setprecision(2);
    int n = 10000000;
    fac[0] = 1;
    for (int i = 1; i <= n; i ++ ) fac[i] = 1ll * fac[i - 1] * i % MOD;
    ifac[n] = fpow(fac[n], MOD - 2);
    for (int i = n; i; i -- ) ifac[i - 1] = 1ll * ifac[i] * i % MOD;
//    int T; cin >> T;
//    while (T -- )
        solve();
#ifdef DEBUG
    cout << "============================" << endl;
    cout << "Program run for " << (clock() - now) / (double)CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif
    return 0;
}

标签:第四场,int,多校,poly,牛客,const,return,mod,size
来源: https://www.cnblogs.com/JYF-AC/p/16538667.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有