2019牛客暑期多校训练(第八场)J-Just Jump

2019牛客暑期多校训练(第八场)J-Just Jump

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


题意

某人要从1走到L点,中间有L-1个点可以走,他每次最少走d步。有m个条件,在第ti步不能走到pi点。问有多少种走法。

思路

先dp求出没有条件时的方案数。然后容斥一下走到条件位置的方案数(减去走到一个条件位置的方案数,加上走到两个条件位置的方案数……)。

坑点

所有数组需要用int类型,在乘法或者三个数相加时要先转为LL类型。


代码

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int maxn=1e7+10;
const int MOD=998244353;
const int N=3005;

struct S
{
    ll t,p;
} pos[N];

int f[maxn],nf[maxn];

int pow_(int x,int y)
{
    int ret=1;
    while (y)
    {
        if (y&1)
            ret=1ll*ret*x%MOD;
        x=1ll*x*x%MOD;
        y>>=1;
    }
    return ret;
}

void init()
{
    f[0]=nf[0]=1;
    for (int i=1; i<maxn; i++)
        f[i]=1ll*f[i-1]*i%MOD;
    nf[maxn-1]=pow_(f[maxn-1],MOD-2);
    for (int i=maxn-1; i; i--)
        nf[i-1]=1ll*nf[i]*i%MOD;
}

int C(int x,int y)
{
    return 1ll*f[x]*nf[y]%MOD*nf[x-y]%MOD;
}

bool cmp(S aa,S bb)
{
    return aa.p<bb.p;
}

int dp[maxn],pre[maxn];
ll tmp[N];

int main()
{
    init();
    int l,d,m;
    ll ans=0;
    scanf("%d%d%d",&l,&d,&m);
    for(int i=1; i<=m; i++)
    {
        scanf("%lld%lld",&pos[i].t,&pos[i].p);
    }
    sort(pos+1,pos+1+m,cmp);
    pre[0]=1;
    for(int i=1; i<d; i++)
    {
        pre[i]=pre[i-1];
    }
    for(int i=d; i<=l; i++)
    {
        dp[i]=pre[i-d];
        pre[i]=(pre[i-1]+dp[i])%MOD;
    }
    tmp[0]=1;
    for(int i=1; i<=m; i++)
    {
        for(int j=0; j<i; j++)
        {
            if(pos[i].t<pos[j].t||pos[j].p==pos[i].p)
                continue;
            if(1ll*d*(pos[i].t-pos[j].t)-(pos[i].p-pos[j].p)>0)
                continue;
            tmp[i]=(tmp[i]+1ll*tmp[j]*C(((pos[i].p-pos[j].p)-((pos[i].t-pos[j].t))*(d-1)-1),((pos[i].t-pos[j].t-1)))%MOD)%MOD;
        }
        tmp[i]=(MOD-tmp[i])%MOD;
    }
    for(int i=0; i<=m; i++)
    {
        ans=(ans+1ll*tmp[i]*dp[l-pos[i].p]%MOD)%MOD;
    }
    printf("%lld\n",ans);
    return 0;
}


官方题解

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值