ICode9

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

2021CCPC威海 M.810975

2022-08-07 15:35:33  阅读:155  来源: 互联网

标签:return int LL poly 2021CCPC M.810975 威海 size MOD


2021CCPC威海 M.810975

题意:问构造出长度为 \(n\) 的01串,有 \(m\) 个1,其中最长连续 \(1\) 的段长度恰好为 \(k\) 的方案数。

知识点:容斥,多项式快速幂

先推荐一个类似的题目 HDU6397 Character Encoding

这题有两种方法,先说简单的那种

可以先解决将 \(m\) 个 \(1\) 插入到 \(n - m + 1\) 个空中,其中最长连续 \(1\) 的段长度不超过 \(k\) 的方案数。

这个问题等价与问

\[\sum_{i=1}^{n-m+1}x_i = m(0 \le x_i \le k) \]

方程组非负整数解的个数

于是对于每个 \(x_i\) 有生成函数 \(\sum_{i=0}^k x^i\)

得到答案多项式为

\[G(x) = (\sum_{i=0}^k x^i)^{n-m+1} \]

这个可以用多项式快速幂求出

\([x^m]G(x)\) 即是答案

当然这个是最长段不超过 \(k\) 的答案,只需要减去最长段不超过 \(k-1\) 的答案即可

注意特判即可

#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;
typedef pair<LL,LL> PLL;
const int INF = 0x3f3f3f3f, N = 1e5 + 10;
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] = 1ll * 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;

inline void solve() {
    int n, m, k; cin >> n >> m >> k;
    if (m > n || k > m) {cout << 0 << endl; return ;}
    if (m == 0) {cout << 1 << endl; return ;}
    if (n == 0) {cout << 1 << endl; return ;}
    if (k == 0) {cout << 0 << endl; return ;}
    poly a(k + 1);
    for (int i = 0; i <= k; i ++ ) a[i] = 1;
    a = (a.ln(m + 1) * (n - m + 1)).exp(m + 1);
    if (k == 1) {cout << a[m] << endl; return ;}
    poly b(k);
    for (int i = 0; i < k; i ++ ) b[i] = 1;
    b = (b.ln(m + 1) * (n - m + 1)).exp(m + 1);
    cout << (a[m] - b[m] + MOD) % MOD << 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 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;
}

接下来说另外一种方法

看回这个式子

\[\sum_{i=1}^{n-m+1}x_i = m(0 \le x_i \le k) \]

先考虑没有 \(k\) 的限制,问题等价于 \(\sum_{i=1}^{n-m+1} x_i = m + k\) 的正整数解个数

可以隔板法得到答案 \(m + k - 1 \choose n-m+1\)

考虑容斥原理,分割成这样一个问题

设 $ans_k $ 为 \(\sum_{i=1}^{n-m+1} x_i = m (0 \le x_i \le k)\) 解的个数

这个解的方法可以参考 HDU6397 Character Encoding

则答案为 \(ans_k - ans_{k-1}\)

注意特判

#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;
typedef pair<LL,LL> PLL;
const int INF = 0x3f3f3f3f, N = 3e5 + 10;
const int MOD = 998244353;
const double eps = 1e-6;
const double PI = acos(-1);
inline int lowbit(int x) {return x & (-x);}

LL f1[N], f2[N];
LL q_pow(LL a, LL b, LL p) {
    LL res = 1;
    for (; b; b >>= 1) {
        if (b & 1) res = res * a % p;
        a = a * a % p;
    }
    return res;
}
LL C(LL n, LL m) {
    if (n < m) return 0;
    if (n < 0 || m < 0) return 0;
    if (n == m) return 1;
    return f1[n] * f2[m] % MOD * f2[n - m] % MOD;
}
LL calc(LL n, LL m, LL k) {
    LL res = 0;
    int ops = 1;
    for (LL i = 0; i <= m; i ++ ) {
        res = (res + 1ll * ops * C(m, i) * C(m + k - 1 - i * n, m - 1) % MOD + MOD) % MOD;
        ops *= -1;
    }
    return res;
}
inline void solve() {
    LL n, m, k; cin >> n >> m >> k;
    if (m > n || k > m) {cout << 0 << endl; return ;}
    if (m == 0) {cout << 1 << endl; return ;}
    if (n == 0) {cout << 1 << endl; return ;}
    if (k == 0) {cout << 0 << endl; return ;}
    cout << (calc(k + 1, n - m + 1, m) - calc(k, n - m + 1, m) + MOD) % MOD << 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 = 300000;
    f1[0] = 1;
    for (int i = 1; i <= n; i ++ ) f1[i] = f1[i - 1] * i % MOD;
    f2[n] = q_pow(f1[n], MOD - 2, MOD);
    for (int i = n; i; i -- ) f2[i - 1] = f2[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;
}

标签:return,int,LL,poly,2021CCPC,M.810975,威海,size,MOD
来源: https://www.cnblogs.com/JYF-AC/p/16559122.html

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

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

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

ICode9版权所有