【CF559C】 Gerald and Giant Chess(计数,方案数DP,数论)

题意:给出一个棋盘为h*w,现在要从(1,1)到(h,w),其中有n个黑点不能走,问有多少种可能从左上到右下

       (1 ≤ h, w ≤ 105, 1 ≤ n ≤ 2000),答案模10^9+7

思路:从(1,1)到(n,m)的方案数是c(n+m-2,n-1)

        考虑不能走黑点

        设dp[i]为从(1,1)走到(x[i],y[i]),中途没有走过任何一个黑点的方案数

        dp[i]=dp[i]-dp[j]*c(x[i]+y[i]-x[j]-y[j],x[i]-x[j]) (x[j]<=x[i]且y[j]<=y[i]) 

        除以阶乘取模用线性求逆元

       

 1 const mo=1000000007;
 2 var x,y:array[1..10000]of longint;
 3     dp:array[1..10000]of int64;
 4     exf,fac:array[0..200000]of int64;
 5     n,m,k,i,j:longint;
 6 
 7 procedure swap(var x,y:longint);
 8 var t:longint;
 9 begin
10  t:=x; x:=y; y:=t;
11 end;
12 
13 function c(x,y:longint):int64;
14 begin
15 // if y=0 then exit(1);
16  exit(fac[x]*exf[y] mod mo*exf[x-y] mod mo);
17 end;
18 
19 procedure qsort(l,r:longint);
20 var i,j,mid1,mid2:longint;
21 begin
22  i:=l; j:=r; mid1:=x[(l+r)>>1]; mid2:=y[(l+r)>>1];
23  repeat
24   while (mid1>x[i])or(mid1=x[i])and(mid2>y[i]) do inc(i);
25   while (mid1<x[j])or(mid1=x[j])and(mid2<y[j]) do dec(j);
26   if i<=j then
27   begin
28    swap(x[i],x[j]);
29    swap(y[i],y[j]);
30    inc(i); dec(j);
31   end;
32  until i>j;
33  if l<j then qsort(l,j);
34  if i<r then qsort(i,r);
35 end;
36 
37 begin
38 // assign(input,'1.in'); reset(input);
39  //assign(output,'1.out'); rewrite(output);
40  readln(n,m,k);
41  for i:=1 to k do read(x[i],y[i]);
42  inc(k); x[k]:=1; y[k]:=1;
43  inc(k); x[k]:=n; y[k]:=m;
44  qsort(1,k);
45  fac[0]:=1;
46  for i:=1 to n+m do fac[i]:=fac[i-1]*i mod mo;
47  exf[0]:=1; exf[1]:=1;
48  for i:=2 to n+m do exf[i]:=exf[mo mod i]*(mo-mo div i) mod mo;
49  for i:=1 to n+m do exf[i]:=exf[i-1]*exf[i] mod mo;
50  dp[1]:=1;
51  for i:=2 to k do
52  begin
53   dp[i]:=c(x[i]+y[i]-2,x[i]-1);
54   for j:=2 to i-1 do
55    if y[j]<=y[i] then
56    begin
57     dp[i]:=dp[i]-dp[j]*c(x[i]-x[j]+y[i]-y[j],x[i]-x[j]);
58     dp[i]:=(dp[i] mod mo+mo) mod mo;
59    end;
60 61  end;
62  writeln(dp[k]);
63 
64  //close(input);
65  //close(output);
66 end.
原文地址:https://www.cnblogs.com/myx12345/p/6030149.html