2019牛客暑期多校赛第八场 J Just Jump 组合数学,容斥,dp

链接:https://ac.nowcoder.com/acm/contest/888/J
来源:牛客网

题目描述

Gromah and LZR have entered the final level. In this level, they need to cross the sea of death to gain the treasures.

The sea of death is of width L​, and there are L−1stones inside the sea. Assume that Gromah and LZR are at position 0initially, that the treasures are at position L​, and that stones are at position 1,2,⋯ ,L−1respectively. So Gromah and LZR can jump on the stones to cross the sea.

Unfortunately, the stones are not stable. To ensure safety, Gromah and LZR should go forward at least d positions each time. Formally, if they are at position x​ currently, they should jump onto the positions not less than x+d. Moreover, they can't be at positions greater than L in any time, which means that the destination of their last jump should be exactly position L​, or the treasure keepers will see them and come to eat them.

More unfortunately, the Infernos under the sea will attack them m times in total, each attack can be described as a tuple (t,p), denoting that the stone at position p​ will be attacked right after their t jump, which means their destination of t jump can't be position p​.

But fortunately, here comes the farmer(mentioned in problem I but not necessary to care in this problem) and he tells Gromah and LZR all the attack plans, so they can work out some jumping plans according to the information given by the farmer to get to the destination without being attacked.

Please help them determine the number of jumping plans satisfying all the restrictions described above. Since the number may be very large, you should report it modulo 998244353.

Two jumping plans are considered different if there exists at least one t that their positions after t jump are different in two plans.

输入描述:

The first line contains three positive integers L,d,m, denoting the width of the sea, the lower bound of jumping distance, and the number of attacks.

Following m​ lines each contains two positive integers t,p denoting an attack (t,p).

1≤d≤L≤10^7,   1≤t,p<L,   1≤m≤3000

m attacks are pairwise distinct, where two attacks (t1,p1),(t2,p2)are considered different if t1≠t2​ or p1≠p2 or both.

输出描述:

Print a non-negative integer in one line, denoting the answer modulo 998244353.

示例1

输入

5 2 1
1 2

输出

2

说明

不考虑攻击有3条路径:0->2->5, 0->3->5 ,0->5. 然后考虑第一步不能跳到2,那么就只剩下两条路径。

题解:

牛客网给的题解:

解释一下C(p-dt+t-1,t-1)怎么来的,这个问题等价于下边这个问题:

有p个相同的球,放到t个不同的盒子里,每个盒子至少d个球的方案数。

那么先将t个盒子每个盒子里放d个,还剩下p-dt个,然后问题转化成:

把p-dt个相同的球,放到t个不同的盒子里,盒子允许为空的方案数。那么就是C(p-dt+t-1,t-1).

这是8种盒子放球模型中的一种,用隔板法算出来的,不知道的百度一下看看就懂了。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e7+5;
const int N=3003;
const int mod=998244353;
ll fac[maxn],ni[maxn];
ll L,d,m;
ll sum[maxn],s[maxn],dp[N];
pair<ll,ll> p[N];
ll ksm(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1) ans=ans*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return ans;
}
ll C(ll n,ll m){
    if(n<0||m<0||n<m) return 0;
    return fac[n]*ni[m]%mod*ni[n-m]%mod;
}
void init(){
    fac[0]=1;
    for(int i=1;i<maxn;i++) fac[i]=fac[i-1]*i%mod;
    ni[maxn-1]=ksm(fac[maxn-1],mod-2);
    for(int i=maxn-2;i>=0;i--) ni[i]=ni[i+1]*(i+1)%mod;
}
int main(){
    init();
    scanf("%lld%lld%lld",&L,&d,&m);
    for(int i=0;i<m;i++){
        scanf("%lld%lld",&p[i].first,&p[i].second);
    }
    sort(p,p+m);
    s[0]=sum[0]=1;
    for(int i=1;i<=L;i++){
        if(i<d) s[i]=0;
        else s[i]=sum[i-d];
        sum[i]=(sum[i-1]+s[i])%mod;
    }
    ll ans=s[L];
    for(int i=0;i<m;i++){
        ll t=p[i].first;
        ll h=p[i].second;
        dp[i]=C(h-t*d+t-1,t-1);
        for(int j=0;j<i;j++){
            ll tt=p[j].first;
            ll hh=p[j].second;
            ll tem=dp[j]*C(h-hh-(t-tt)*d+t-tt-1,t-tt-1)%mod;
            dp[i]=(dp[i]-tem+mod)%mod;
        }
        ans=(ans-dp[i]*s[L-h]%mod+mod)%mod;
    }
    printf("%lld\n",ans);
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值