题目链接
思路:
补充:
1.由于数据范围达到1e7,只能通过lucas定理计算组合数。
2这个公式的推导过程:需要刚好花时间ti到达距离pi,每次移动至少d的方案数,等价于花时间ti到达距离pi-dti,每次不一定要移动的方案数。这个问题又可以转化成从pi-dti+ti-1 个点中选取ti-1个点的方案数。
3.gu[u][i] :受到含第i次攻击在内,一共收到奇/偶次攻击的情况数,再根据容斥原理,奇加偶减。
(这种题真是太难debug了,基本上就是照着ac代码一步一步调)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll ;
const int MOD=998244353;
const int MAXN=1e7+5;
ll INV[MAXN],fac[MAXN],fac_p[MAXN];
ll num[2][MAXN],sum[MAXN],f[MAXN];
int L,d,m;
struct node {
ll p,t;
bool operator<(node y){
return t<y.t;
}
}nodes[3005];
ll powa(ll a, ll b){
ll ans = 1;
a %= MOD;
while(b){
if(b & 1)ans = (ans % MOD) * (a % MOD) % MOD;
b /= 2;
a = (a % MOD) * (a % MOD) % MOD;
}
ans %= MOD;
return ans;
}
ll C(ll n, ll m){
if(n<0||m<0)return 0;
if(n<m) return 0;
return fac[n]*fac_p[n-m]%MOD*fac_p[m]%MOD;
}
ll Lucas(ll n, ll m){
if(n<0||m<0) return 0;//一定要提前判断n,m的正负,否则算出来的结果会相差很大。
if(m==0) return 1;
return C(n %MOD, m % MOD) * Lucas(n / MOD, m / MOD) % MOD;
}
void init(){
fac[0]=1;
for(int i=1;i<MAXN;i++) fac[i]=fac[i-1]*i%MOD;
fac_p[MAXN-1]=powa(fac[MAXN-1],MOD-2);
for(int i=MAXN-2;i>=1;i--) fac_p[i]=fac_p[i+1]*(i+1)%MOD;
}
int main()
{
scanf("%d%d%d",&L,&d,&m);
f[0]=sum[0]=1;
init();
for(int i=1;i<=L;i++)
{
if(i<d) f[i]=0;
else f[i]=sum[i-d];
sum[i]=(sum[i-1]+f[i])%MOD;
}
nodes[0].p=nodes[0].t=0;
for(int i =1;i<=m;i++) {
scanf("%lld %lld",&nodes[i].t,&nodes[i].p);
}
sort(nodes+1,nodes+m+1);
ll ans=f[L];
num[0][0]=1;
for(int i=1;i<=m;i++){
for(int k=0;k<2;k++){
for(int j=0;j<i;j++){
ll dp=nodes[i].p-nodes[j].p,dt=nodes[i].t-nodes[j].t;
//printf("%lld %lld:%lld\n",dp-d*dt+dt-1,dt-1,Lucas(dp-d*dt+dt-1,dt-1));
num[k][i]=(num[k][i]+num[1-k][j]*Lucas(dp-d*dt+dt-1,dt-1)%MOD)%MOD;
}
}
ans=(ans+(num[0][i]-num[1][i]+MOD)%MOD*f[L-nodes[i].p]%MOD)%MOD;
}
printf("%lld\n",ans);
}