[CF559C]Gerald and Giant Chess

给定一个坐标系,求从点$(1,1)$到点$(n,m)$有多少种方案数。 其中有$k$个点不能经过,会给定这$k$个点的坐标。

读入: 第一行:$n$,$m$,$k$ 接下来$k$行,每行两个整数,表示不能经过的点的坐标

输出:从$(1,1)$到(n,m)的方案数,对$10^9$+$7$取模($n,m \le 10^5$,$k \le 2*10^3$)

很有意思的一道计数题

首先我们可以发现,在没有任何限制的情况下,从$(1,1)$走到$(n,m)$的方案数为$C(n+m-2,m-1)$

因为有了黑点不能走的限制,我们发现直接求不好求,所以考虑容斥

对于任意两种方案,显然如果它们路径上经过的第一个黑点是不同的,那么他们一定是不同的

我们现将黑点坐标排序,设$dp_i$表示从$(1,1)$不经过其他黑点到达$i$号黑点的方案数

那么dp方程转移即为:

$dp_i$=$C(x_i+y_i-2,x_i-1)$-$dp_j*C(x_i+y_i-x_j-y_j,x_i-x_j)(x_j \le x_i,y_j \le yi)$

为了方便计算,把$(n,m)$也当做一个黑点即可

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #define M 200010
 5 #define mod 1000000007
 6 #define int long long
 7 using namespace std;
 8 int n,m,q;
 9 int h[M],inv[M],dp[M];
10 struct black{
11     int x,y;
12 }a[M];
13 bool cmp(black a1,black a2){
14     return a1.x<a2.x||(a1.x==a2.x&&a1.y<a2.y);
15 }
16 int C(int n,int m){
17     return h[n]*inv[m]%mod*inv[n-m]%mod;
18 }
19 int power(int a,int b){
20     int ans=1;
21     while(b){
22         if(b&1) ans=ans*a%mod;
23         b>>=1; a=a*a%mod;
24     }
25     return ans;
26 }
27 void pre(){
28     h[0]=1;inv[0]=1;
29     for(int i=1;i<=200000;i++) h[i]=i*h[i-1]%mod,inv[i]=power(h[i],mod-2);
30 }
31 #undef int
32 int main(){
33     #define int long long
34     pre(),cin>>n>>m>>q;
35     for(int i=1;i<=q;i++) cin>>a[i].x>>a[i].y;
36     a[++q]=(black){n,m},sort(a+1,a+1+q,cmp);
37     for(int i=1;i<=q;i++){
38         dp[i]=C(a[i].x+a[i].y-2,a[i].x-1);
39         for(int j=1;j<i;j++)
40             if(a[j].x<=a[i].x&&a[j].y<=a[i].y)
41                 dp[i]=(dp[i]-C(a[i].x-a[j].x+a[i].y-a[j].y,a[i].x-a[j].x)*dp[j]%mod+mod)%mod;
42     }
43     cout<<dp[q]<<endl;
44     return 0;
45 }

PS:最近不知道为啥突然就变码风了,第一次大括号不换号QwQ

猜你喜欢

转载自www.cnblogs.com/Slrslr/p/9836523.html