牛客多校8 J Just Jump

 思路:枚举第一个碰到的被攻击的点

#include <bits/stdc++.h>
using namespace std;
typedef int lint;
typedef long long LL;
const int maxn = 10000005;
const int maxm = 3005;
const int mod = 998244353;
typedef unsigned long long ll;
const ll oo=mod;
ll frac[maxn], carf[maxn];
ll inv(ll x){
    if (x==1) return 1;
    else return (oo-oo/x)*inv(oo%x)%oo;
}
void init(){
    frac[0]=1;
    for (int i=1;i<=10000001;i++)
        frac[i]=frac[i-1]*i%oo;
    carf[10000001]=inv(frac[10000001]);
    for (int i=10000001;i>=1;i--)
        carf[i-1]=carf[i]*i%oo;
}

ll C(int n, int m){
    if (m>n ) return 0;
    else return frac[n]*carf[n-m]%oo*carf[m]%oo;
}
struct point{
    lint t,p;
    point( lint tt = 0,lint pp = 0 ){
        t = tt;p = pp;
    }
    bool operator < ( const point&b )const{
        if( p == b.p ) return t < b.t;
        return t < b.t;
    }
};
vector<point> ve;
LL g[maxn],S[maxn],f[maxm];
int main(){
    init();
    //cout << C( 0,0 ) << endl;
    lint L,d,m,t,p;
    scanf("%d%d%d",&L,&d,&m);
    for( lint i = 1;i <= m;i++ ){
        scanf("%d%d",&t,&p);
        ve.push_back( point( t,p ) );
    }
    sort( ve.begin(),ve.end() );
    g[0] = 1;
    S[0] = 1;
    for( int i = 1;i <= d-1;i++ ) g[i] = 0,S[i] = S[i-1];
    for( int i = d;i <= L;i++ ){
        g[i] = S[i-d];
        S[i] = (S[i-1]+g[i])%mod;
    }
    for( lint i = 0; i< ve.size();i++ ){
        if( ve[i].p-(LL)( d-1 )*ve[i].t-1 >= 0 )f[i] = C( ve[i].p-(LL)( d-1 )*ve[i].t-1,ve[i].t-1 );
        for( lint j = 0;j < i;j++ ){
            if( ve[i].p > ve[j].p && ve[i].t > ve[j].t ) {
                if(  ve[i].p-ve[j].p-(LL)(d-1)* (ve[i].t-ve[j].t) -1 >= 0 )f[i] = (f[i] - f[j] * C( ve[i].p-ve[j].p-(LL)(d-1)* (ve[i].t-ve[j].t) -1 ,ve[i].t-ve[j].t-1 )%mod + mod)%mod;
            }
        }
    }
    LL ans = g[L];
    for( lint i = 0;i < ve.size();i++ ){
        ans = (ans + mod - f[i]*g[ L-ve[i].p ]%mod  )%mod ;
    }
    cout << ans << endl;
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值