题目链接:Just Jump
题意:
你要从0跳到L,每一次跳的距离不能小于d,有m个攻击(t,p),表示当第t次跳跃到p位置时会被攻击,问有多少种跳跃方式可以从0跳到L且不被攻击;
看完官方题解写的,就不做分析了。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e7+7;
const ll mod=998244353;
ll inv[maxn],f[maxn],g[3007][2];
ll dp[maxn],tmp[maxn];
struct node{int t,pos;} p[3007];
bool cmp(node a,node b) {return a.t<b.t;}
ll C(int a,int b)
{
return f[a]*inv[b]%mod*inv[a-b]%mod;
}
int main()
{
int n,d,m;scanf("%d%d%d",&n,&d,&m);
for (int i=1;i<=m;i++) scanf("%d%d",&p[i].t,&p[i].pos);
f[0]=f[1]=1;inv[0]=inv[1]=1;
for (int i=2;i<=n;i++) {f[i]=f[i-1]*i%mod;inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;}
for (int i=2;i<=n;i++) inv[i]=inv[i]*inv[i-1]%mod;
sort(p+1,p+m+1,cmp);
dp[0]=tmp[0]=g[0][0]=1;
for (int i=1;i<=n;i++)
{
dp[i]=(i>=d?tmp[i-d]:0);
tmp[i]=(tmp[i-1]+dp[i])%mod;
}
ll sum;
ll res,ans=dp[n];
for (int i=1;i<=m;i++)
{
for (int j=0;j<i;j++)
{
res=p[i].t-p[j].t;sum=p[i].pos-p[j].pos-1ll*d*res;
if(res>0 && sum>=0)
{
ll kk=C(sum+res-1,res-1);
g[i][0]=(g[i][0]+g[j][1]*kk)%mod;
g[i][1]=(g[i][1]+g[j][0]*kk)%mod;
}
}
ans=(ans+1ll*g[i][0]*dp[n-p[i].pos]-1ll*g[i][1]*dp[n-p[i].pos])%mod;
}
printf("%lld\n",(ans+mod)%mod);
return 0;
}