题意
有一条长为 L L L的河,你在位置 0 0 0你要通过这条长为 L L L的河到达 L L L,河中从 1 , 2 , 3 , ⋯   , L − 1 1,2,3,\cdots,L-1 1,2,3,⋯,L−1有石子可以踩上去通过,你每一次所走的距离必须要大于等于 d d d,并且还存在 m m m次攻击,每一次攻击由二元组 ( t i , p i ) (t_i,p_i) (ti,pi)组成,表示,在 t i t_i ti次跳跃时落在 p i p_i pi时你就会被攻击,若被攻击你就会失败,求从 0 0 0出发到达 L L L的方法数
思路
先考虑没有攻击时总的方案数,有
f
[
i
]
=
f
[
1
]
+
f
[
2
]
+
f
[
3
]
+
⋯
+
f
[
i
−
d
]
f[i]=f[1]+f[2]+f[3]+\cdots+f[i-d]
f[i]=f[1]+f[2]+f[3]+⋯+f[i−d]
f
[
i
+
1
]
=
f
[
1
]
+
f
[
2
]
+
f
[
3
]
+
⋯
+
f
[
i
−
d
]
+
f
[
i
+
1
−
d
]
f[i+1]=f[1]+f[2]+f[3]+\cdots+f[i-d]+f[i+1-d]
f[i+1]=f[1]+f[2]+f[3]+⋯+f[i−d]+f[i+1−d]
可以发现我们要是每次维护一个前缀和就可以
O
(
1
)
O(1)
O(1)求得的
f
[
i
]
f[i]
f[i]
f
[
i
]
=
s
u
m
[
i
−
1
−
d
]
+
f
[
i
−
d
]
f[i]=sum[i-1-d]+f[i-d]
f[i]=sum[i−1−d]+f[i−d]
所以可以在
O
(
L
)
O(L)
O(L)的时间求的总的方法数
f
[
L
]
f[L]
f[L]
那么最终的答案我们可以考虑用
f
[
L
]
f[L]
f[L]去减去被攻击时的方案数,就是最终的答案。
我们考虑一下每一个
(
t
,
p
)
(t,p)
(t,p)的贡献,可以分成两部分考虑
- 从 0 0 0跳 t t t次到达 p p p,那么我们先考虑没有每次至少跳 d d d步的限制,那么就是从 0 0 0到 p p p,跳 t t t次,每次可以跳任意步数。转换一下可以变为有 p p p个球,放到 t t t个箱子里,箱子可以为空的方案数,那就可以套用经典的隔板法那么答案就是 C p + t − 1 t − 1 C_{p+t-1}^{t-1} Cp+t−1t−1。现在有了每次至少跳 d d d的限制那么我们可以在一开始 p − d t p-dt p−dt,那么剩下的这段距离就是原来的无限制的方案数了,那么方案数就是 C p − d t + t − 1 t − 1 C_{p-dt+t-1}^{t-1} Cp−dt+t−1t−1
- 从 p p p跳到 L L L的方案数,这段的方案数其实和从 0 0 0跳到 L − p L-p L−p是等价,那么方案数就是 f [ L − p ] f[L-p] f[L−p]
那么每一个攻击的贡献就是这两部分的方案数之积了,解决了某一个攻击的贡献,我们还要考虑一下攻击和攻击之间的关系。我们可以先把攻击按照跳的次数排个序,由于题目中跳跃的次数是没有重复的,我们通过排序后,令
d
p
[
i
]
dp[i]
dp[i]为跳
t
i
t_i
ti次第一次被攻击时的方案数,那么有转移方程
d
p
[
i
]
=
C
p
i
−
d
t
i
+
t
i
−
1
t
i
−
1
−
∑
j
=
0
i
−
1
d
p
[
j
]
∗
C
p
i
−
p
j
−
d
(
t
i
−
t
j
)
+
t
i
−
t
j
−
1
t
i
−
t
j
−
1
dp[i]=C_{p_i-dt_i+t_i-1}^{t_i-1}-\sum_{j=0}^{i-1}dp[j]*C_{p_i-pj-d(t_i-t_j)+t_i-t_j-1}^{t_i-t_j-1}
dp[i]=Cpi−dti+ti−1ti−1−j=0∑i−1dp[j]∗Cpi−pj−d(ti−tj)+ti−tj−1ti−tj−1
d
p
[
i
]
dp[i]
dp[i]的方案数是从
0
0
0到
p
i
p_i
pi跳
t
i
t_i
ti次的方案数减去,第
j
j
j(
0
≤
j
<
i
0\leq j<i
0≤j<i)次攻击作为第一次被攻击时的方案数乘上从第
j
j
j次攻击跳到第
i
i
i次攻击的方案数,就是第
i
i
i次攻击作为第一次被攻击时的方案数了。
那么最终的答案就是
a
n
s
=
f
[
L
]
−
∑
i
=
0
m
−
1
d
p
[
i
]
∗
f
[
L
−
p
i
]
ans=f[L]-\sum_{i=0}^{m-1}dp[i]*f[L-p_i]
ans=f[L]−i=0∑m−1dp[i]∗f[L−pi]
组合数预处理处理到1e7就好了但是,可能
d
∗
t
i
d*t_i
d∗ti可能会爆int,都改成long long 保险一点
#include<bits/stdc++.h>
using namespace std;
const int N=1e7+1234;
const int mod=998244353;
struct node
{
int t,p;
}a[3005];
long long f[N],sum[N];
long long fac[N],inv[N];
long long dp[N];
long long quickmod(long long a,long long b)
{
long long ans=1;
while(b)
{
if(b%2==1)
ans=ans*a%mod;
a=a*a%mod;
b=b/2;
}
return ans;
}
long long C(long long n,long long m)
{
if(n<0||m<0) return 0;
if(n<m)
return 0;
return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
bool cmp(node a,node b)
{
return a.t<b.t;
}
int main()
{
fac[0]=1;
for(int i=1;i<N;i++)
fac[i]=fac[i-1]*i%mod;
inv[N-1]=quickmod(fac[N-1],mod-2);
for(int i=N-2;i>=0;i--)
inv[i]=inv[i+1]*(i+1)%mod;
int L,d,m;
scanf("%d%d%d",&L,&d,&m);
f[0]=sum[0]=1;
for(int i=1; i<=L; i++)
{
if(i<d)
f[i]=0;
else
{
f[i]=(sum[i-1-d]+f[i-d])%mod;
}
sum[i]=(sum[i-1]+f[i])%mod;
}
for(int i=0;i<m;i++)
scanf("%d%d",&a[i].t,&a[i].p);
sort(a,a+m,cmp);
long long ans=f[L];
for(int i=0;i<m;i++)
{
dp[i]=C(a[i].p-1ll*a[i].t*d+a[i].t-1,a[i].t-1);
for(int j=0;j<i;j++)
{
dp[i]=(dp[i]-dp[j]*C(a[i].p-a[j].p-1ll*d*(a[i].t-a[j].t)+a[i].t-a[j].t-1,a[i].t-a[j].t-1)%mod)%mod;
}
ans=(ans-dp[i]*f[L-a[i].p]%mod+mod)%mod;
}
printf("%lld\n",ans);
return 0;
}