题意:
曾经有一道叫做迷雾森林的题目,然而牛牛认为地图中的障碍太多,实在是太难了,所以删去了很多点,出了这道题。
牛牛给出了一个n行m列的网格图
初始牛牛处在最左下角的格点上(n+1,1),终点在右上角的格点(1,m+1)
现在它想知道,从起点走到终点,只能向上或向右走,一共有多少种走法呢?
需要注意的是,除了起点和终点外,其它的每个格点都有可能有障碍,无法通过。
请注意格子与格点的区别
题解:
参考博客
对于 n,m<=1000 的点:DP
对于 n,m<=100000 的点,因为k很小,考虑使用容斥原理,我们定义一个work函数,work是指右移a次上移b次有多少种移法
假设只有一个点(x,y)不能走,总方案是C(m+n,n),减去经过这个点方案C(x+y,x) * C(n-x+n-y,n-x)
即 C(m+n,n)- C(x+y,x) * C(n-x+n-y,n-x)
如果有多个障碍点的话,我们考虑什么样的点彼此会共同影响,
图中绿色为障碍点,蓝色为路线,我们不难发现当点与点之间存在偏序关系的时候,就会彼此共同影响,如何找偏序关系,当
(x[j]>=x[i]&&y[j]>=y[i])(i是左下方的点,j是右上方的点)时说明满足条件
代码:
#include<bits/stdc++.h>
#define LL long long
using namespace std;
LL n,m,k,s,t;
bool f[1005][1005];
LL dp[1005][1005];
LL x[10],y[10];
LL mod=998244353;
LL ksm(LL a) {LL b=mod-2;LL ans=1;while(b) {if(b&1)ans=(a*ans)%mod;a=a*a%mod;b>>=1;}return ans;
}
LL ni[100005];
void csh() {for(LL i=1; i<=100000; i++)ni[i]=ksm(i);
}
LL C(LL a,LL b) {LL a1=1;for(LL i=b; i>=b-a+1; i--)a1=a1*i%mod;for(LL i=1; i<=a; i++)a1=(a1*ni[i])%mod;return a1;
}
LL work(LL a,LL b) {return C(a,a+b);
}
int main() {cin>>n>>m>>k;m++;n++;if(n<=1000&&m<=1000) {for(LL i=1; i<=k; i++) {cin>>s>>t;f[s][t]=1;}dp[n][1]=1;for(LL i=n; i>0; i--)for(LL j=1; j<=m; j++)if((i!=n||j!=1)&&f[i][j]!=1)dp[i][j]=(dp[i+1][j]+dp[i][j-1])%mod;cout<<dp[1][m]<<"\n";}else {csh();LL ans=work(n-1,m-1);for(LL i=1; i<=k; i++) {cin>>x[i]>>y[i];x[i]=n-x[i];y[i]--;ans=(ans-work(x[i],y[i])*work(n-x[i]-1,m-y[i]-1))%mod;}for(LL i=1; i<=k; i++)for(LL j=i+1; j<=k; j++)if(x[i]+y[i]>x[j]+y[j]) {swap(x[i],x[j]);swap(y[i],y[j]);}if(k>=2)for(LL i=1; i<=k; i++)for(LL j=i+1; j<=k; j++)if(x[j]>=x[i]&&y[j]>=y[i])ans=(ans+work(x[i],y[i])*work(x[j]-x[i],y[j]-y[i])%mod*work(n-x[j]-1,m-y[j]-1))%mod;cout<<(ans+mod)%mod<<endl;}return 0;
}
/*
a b+a
*/