• [ICPC2020上海E] The Journey of Geor Autumn


    [ICPC2020上海E] The Journey of Geor Autumn - 组合数学

    Description

    对于给定的 (n,k le 10^7),求有多少个满足这样条件的 (1..n) 全排列:对于任意 (i >k)(a_i > min_{j in [i-k,i)} a_j).

    Solution

    最小的数必须放在 ([1,k]) 中的任意位置 (pos) 上。一旦这个数确定,那么 ([1,pos)) 这段位置区间中可以任意填数,((pos,n]) 这一段构成一个递归的子问题。

    (f[n]) 表示对于一个长度为 (n) 的序列的答案,则

    [f[n] = sum_{j=1}^{min(i,k)} inom{i-1}{j-1} f(i-j) (j-1)! ]

    变形得到

    [frac {f(i)} {i!} = frac 1 i sum_{j=1}^{min(i,k)} frac{f(i-j)}{(i-j)!} ]

    前缀和优化一下即可。

    阶乘辅助是线性预处理逆元的简单而有效的手段。

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    const int mod = 998244353;
    const int N = 1e+7 + 5;
    
    int s[N], inv[N], ifac[N], fac[N], n, k;
    
    int qpow(int p, int q)
    {
        return (q & 1 ? p : 1) * (q ? qpow(p * p % mod, q / 2) : 1) % mod;
    }
    
    signed main()
    {
        ios::sync_with_stdio(false);
        cin >> n >> k;
        fac[0] = 1;
        for (int i = 1; i <= n + 1; i++)
            fac[i] = fac[i - 1] * i % mod;
        ifac[n + 1] = qpow(fac[n + 1], mod - 2);
        for (int i = n; i >= 0; i--)
            ifac[i] = ifac[i + 1] * (i + 1) % mod;
        for (int i = 1; i <= n; i++)
            inv[i] = ifac[i] * fac[i - 1] % mod;
        s[0] = 1;
        for (int i = 1; i <= n; i++)
            s[i] = (s[i - 1] + (s[i - 1] - (i - k - 1 < 0 ? 0 : s[i - k - 1]) + mod) % mod * inv[i] % mod) % mod;
        cout << (s[n] - s[n - 1] + mod) % mod * fac[n] % mod << endl;
    }
    
  • 相关阅读:
    常用函数
    小工具
    javascript实现的平方米、亩、公顷单位换算小程序
    在spring boot 项目中使用thymeleaf模板
    IntellJ IDEA 中JAVA代码的任务标记(TODO、FIXME、【XXX】)
    XMPP学习
    iOS绘图教程(个人学习总结)
    iOS: #ifdef DEBUG
    iphone sdk版本宏
    xmpp
  • 原文地址:https://www.cnblogs.com/mollnn/p/14139310.html
Copyright © 2020-2023  润新知