版权声明:本文为博主原创文章,未经博主允许不得转载,欢迎前往zory.cf获得最佳体验 https://blog.csdn.net/Zory_Programmer/article/details/82141579
看到黑色棋子这么少,一定是用总方案数-非法情况得到答案
然后就想着,如果统计每个黑色格子经过的数量,用容斥原理统计的话,怎么计算出多个黑色的情况?显然是无法暴力枚举的,所以就懵逼了
其实,这是因为状态的设计有问题,导致同一条路径被多次计算
重新设计状态,设
表示以黑格子x作为某条【经过黑格子的路径】的第一个黑格子,这样,每条路径只会被它第一个黑格子统计,这样就能不重不漏了
至于任意走的时候的方案数,可以参考前面讲到的多重集全排列
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
namespace mine
{
typedef long long ll;
const int MAX_N=2100;
const ll MOD=1e9+7;
ll qpower(ll a,ll e)
{
ll ans=1;
while(e>0)
{
if(e&1) ans=ans*a%MOD;
a=a*a%MOD;e>>=1;
}
return ans;
}
ll fac[210000],invfac[210000];//debug 开太小了,因为x+y
ll C(int n,int m)
{
return fac[n]*invfac[m]%MOD*invfac[n-m]%MOD;
}
struct Nod
{
int x,y;
}p[MAX_N];
bool cmp(Nod a,Nod b)
{
return a.x<b.x or (a.x==b.x and a.y<b.y);
}
ll f[MAX_N];
void main()
{
fac[0]=1;invfac[0]=1;
for(int i=1;i<=200000;i++) fac[i]=fac[i-1]*i%MOD,invfac[i]=qpower(fac[i],MOD-2);
int h,w,n;scanf("%d%d%d",&h,&w,&n);
for(int i=1;i<=n;i++) scanf("%d%d",&p[i].x,&p[i].y);
sort(p+1,p+n+1,cmp);
p[n+1].x=h;p[n+1].y=w;//等价
for(int i=1;i<=n+1;i++)
{
f[i]=C(p[i].x+p[i].y-2,p[i].x-1);
for(int j=1;j<=i-1;j++)
if(p[j].x<=p[i].x and p[j].y<=p[i].y)
{
f[i]-=f[j]*C(p[i].x-p[j].x+p[i].y-p[j].y,p[i].x-p[j].x)%MOD;
f[i]=(f[i]%MOD+MOD)%MOD;
}
}
printf("%I64d",(f[n+1]%MOD+MOD)%MOD);
}
};
int main()
{
mine::main();
}