传送门
题意:L长的数轴,从0开始跳,每次可以跳>=d的距离,但是有m限制,就是ti时刻不得跳到pi处,求到L的方案数
解:先不考虑m限制,dp很容易推出了,前缀和优化就是O(n)的。然后考虑限制减去,就是求出经过一次pi(限制处)再抵达L的方案数,这里我们很容易想到容斥定理,用容斥来求。官解:
解释一下这个组合数,就是先pi先减去d*ti的最低限制,剩下的就是多余的部分,但是ti次跳跃可能会有0(多余部分) ,下面就看作小球了,因为有0,所以就加入ti个球,现在就是要求小球放入ti个盒子非空了,然后再插入ti-1块隔板即可。
#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define SZ(a) int((a).size())
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int mod=998244353;
const int N=1e7+5,M=3e3+5;
ll dp[N],sum[N],b[M];
struct node {
ll t,p;
}a[M];
bool cmp(node x,node y) {return x.p<y.p;}
ll l,d,m;
ll fac[N],inv[N];
ll fpow(ll x,ll y) {
ll ans=1;
while(y) {
if(y&1) ans=(ans*x)%mod;
x=(x*x)%mod;
y>>=1;
}
return ans;
}
ll C(int n,int m) {
if(m>n || n<0 || m<0) return 0;
ll ans=1;
ans=(ans*fac[n])%mod;
ans=(ans*inv[m])%mod;
ans=(ans*inv[n-m])%mod;
return ans;
}
void init() {
fac[0]=inv[0]=1;
for(int i=1;i<=10000000;i++) fac[i]=(1LL*fac[i-1]*i)%mod;
inv[10000000]=fpow(fac[10000000],mod-2);
for(int i=9999999;i>=1;i--) inv[i]=(1LL*inv[i+1]*(i+1))%mod;
}
ll cal(ll p,ll t) {
p-=t*d;
if(p<0) return 0;
else return C(p+t-1,t-1);
}
ll solve(){
sort(a+1,a+1+m,cmp);
for(int i=1;i<=m;i++) {
b[i]=cal(a[i].p,a[i].t);
for(int j=1;j<i;j++) {
if(a[j].t>a[i].t) continue;
if(a[j].p==a[i].p) continue;
b[i]=(b[i]-1LL*b[j]*cal(a[i].p-a[j].p,a[i].t-a[j].t)+mod)%mod;
}
}
ll res=0;
for(int i=1;i<=m;++i)
res=(res+b[i]*dp[l-a[i].p]%mod)%mod;
return res;
}
int main() {
init();
scanf("%lld%lld%lld",&l,&d,&m);
for(int i=1;i<=m;i++) scanf("%lld%lld",&a[i].t,&a[i].p);
dp[0]=sum[0]=1;
for(int i=1;i<=l;++i){
if(i<d) dp[i]=0,sum[i]=1;
else dp[i]=sum[i-d],sum[i]=(sum[i-1]+dp[i])%mod;
}
printf("%lld\n",(dp[l]-solve()+mod)%mod);
return 0;
}