zoukankan      html  css  js  c++  java
  • I-Just Jump_2019牛客暑期多校训练营(第八场)

    题目链接

    Just Jump

    题意

    有L+1个点,初始在第0个点上,要跳到第L个点,每次至少跳d格,也就是在点x至少要跳到x+d,且有m个限制
    ((t_i, p_i))指跳第(t_i)次不能跳到(p_i)

    题解

    设dp[i]表示从0跳到i且没有限制的方案数,可以预处理。对限制按t从小到大排序,(g[i][0])表示通过了前i-1个限制,踩在了第i个限制上且1-i这些限制踩了偶数个,(g[i][1])表示踩了奇数个限制的方案数,可以(m^2)递推,根据容斥原理加上踩偶次的方案数扣掉踩奇数次的方案数。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
     
    const int mx = 1e7+5;
    const int mod = 998244353;  
    ll dp[mx], fac[mx], invf[mx];
    int g[3005][2];
    int L, d, m;
     
    int pow_mod(ll a, ll b) {
        ll ans = 1;
        while (b > 0) {
            if (b & 1) ans = ans * a % mod;
            a = a * a % mod;
            b /= 2;
        }
        return ans;
    }
     
    struct Node {
        int t, p;
        bool operator < (Node other) const {
            return t < other.t;
        }
    }node[3005];
     
    int C(int x, int y) {
        if (x < y || y < 0 || x < 0) return 0;
        return (1LL * fac[x] * invf[y] % mod * invf[x-y]) % mod;
    }
     
    int calc(int i, int j) {
        if (1LL * (node[j].t-node[i].t)*d > node[j].p-node[i].p) return 0;
        return C(node[j].p-node[i].p-(node[j].t-node[i].t)*d + (node[j].t-node[i].t) - 1, node[j].t-node[i].t-1);
    }
     
    int main() {
        scanf("%d%d%d", &L, &d, &m);
        for (int i = 1; i <= m; i++) scanf("%d%d", &node[i].t, &node[i].p);
        sort(node+1, node+1+m);
        node[0].t = node[0].p = 0;
        dp[0] = 1;
        int sum = 0;
        for (int i = 1; i <= L; i++) {
            if (i-d >= 0) sum = (sum + dp[i-d]) % mod;
            dp[i] = sum;
        }
         
        fac[0] = invf[0] = 1;
        for (int i = 1; i <= L; i++) fac[i] = 1LL * fac[i-1] * i % mod;
        invf[L] = pow_mod(fac[L], mod-2);
        for (int i = L-1; i >= 1; i--) invf[i] = 1LL * invf[i+1] * (i+1) % mod;
     
        g[0][0] = 1; g[0][1] = 0;
        for (int i = 1; i <= m; i++) {
            for (int j = 0; j < i; j++) {
                g[i][0] = (g[i][0] + 1LL * g[j][1] * calc(j, i) % mod) % mod;
                g[i][1] = (g[i][1] + 1LL * g[j][0] * calc(j, i) % mod) % mod;
            }
        }
        ll ans = dp[L];
        for (int i = 1; i <= m; i++) {
            ans += 1LL * (g[i][0] - g[i][1]) * dp[L-node[i].p] % mod;
            ans = (ans % mod + mod) % mod;
        }
        printf("%lld
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    Perl-晶晨2021届笔试题
    数字IC设计流程
    后端一些常考知识点
    sklearn: 利用TruncatedSVD做文本主题分析
    用截断奇异值分解(Truncated SVD)降维
    numpy.linalg.norm(求范数)
    岭回归和lasso回归及正则化
    什么是范数?
    MySQL三大范式和反范式
    汇编知识之EIP寄存器
  • 原文地址:https://www.cnblogs.com/bpdwn-cnblogs/p/11392963.html
Copyright © 2011-2022 走看看