【Gerald and Giant Chess】
一道计数类DP例题~~~
ps:P党似乎不多了……
我这只蒟蒻第一次写题解,而且计数类DP还是早上刚学的,现学现用,或者说是所谓的“浅谈”一番吧!况且这题写题解的人似乎并不多(大佬似乎不屑于光临此题)
进入正题
- 题目大意:扔给你一个h*w的棋盘,并给定n给不可以经过的格子的坐标,和(sang)蔼(xin)可(bing)亲(kuang)地让你计算从(1,1)开始走到(h,w)的合法路径的条数,答案对\(10^9+7\)取模。
看完题后,呵,简单,都做过过河卒这种题吧!递推在手,天下我有!!
大笑着,不经意间瞟了一下数据范围,笑容瞬间凝固……
- $1<=h,w<=10^{5},1<=n<=2000 $
啥玩意?
无奈,出门左转,逃!
够英明的选择,但还有更英明的选择——学习!没错,学习!
好的,依阁下高见,我来学习了。
孺子可教,吭吭,听好了(冒犯):
-
倘若你成了超人,通过了之前无法逾越的格子,那么你走到终点的路径总数是可以用一个组合数搞出来的。不会?那就对了,接着看。从起点走到终点,你必然走了\(h-1\)步往下,\(w-1\)步往右,对吧?总步数就是\(h+w-2\) ,然后想想组合数,整条路径我走了\(h-1\)步往下,剩下\(w-1\)步就确定了。那么换种说法,我从\(h+w-2\)步中选\(h-1\)步往下,就可以确定唯一的一条路径,则总方案数为\(C_{h+w-2}^{h-1}\)种,同理,走\(w-1\)步往下,也可以确定唯一的一条路径,有\(C_{h+w-2}^{w-1}\)种方案数。两者等价。(等价?质疑请了解\(C_n^m=C_n^{n-m}\))
-
但是,棋盘中有些点是不能走的,我们考虑用容斥原理去除多余方案。
其中\(P_i\)表示经过i个不能走的点的路径,但是,此题n<=2000,容斥原理直接炸掉。(况且我也不会容斥原理,我太弱了)
-
但我们不急,不慌,不乱。想想DP,乱设一下,设\(f_i\)表示从(1,1)走到第i个不能走的点,且不经过其它不能走的点的方案数。推一下,设\(x_i,y_i\)为第i个不能通过的点(以\(x_i\)为第一关键字,\(y_i\)为第二关键字排好序后),我们可以用上文推到的东西先算出(1,1)这个点到总方案数,然后依照我们的定义:“不能经过其他无法通过的点”,所以要减去前\(i-1\)个点到此点的方案数(不合定义),就是\(f_i\)了,综上:
- \[f_i=C_{x_i+y_i-2}^{x_i-1}-\sum_{j=1}^{i-1}f_j·C_{x_i+y_i-x_j-x_j}^{x_i-x_j} \]
-
我们可以让终点成为不可通过的点,答案就是\(f_{n+1}\)了。
-
嗯嗯,讲完了。
\(O(n^2)\) 的时间复杂度,完美AC。\(n<=2000\)
那么,再综合解题步骤:
-
以\(x_i\)为第一关键字,\(y_i\)为第二关键字排好序。
-
提前预处理出组合数所需要的逆元(逆元可以自学,复习时我可能会写来巩固一下)。
-
把终点加入\(f\)中,计算\(f_i\)的值,答案就是\(f_{n+1}\)
附上完整代码,放心食用。(pascal的,重点在思路,语言无太大关系)
const p=trunc(1e9)+7;
type
node=record
x,y:int64;
end;
var
fac,inv:array [0..200005] of int64;
f:array [0..3005] of int64;
a,c:array [0..3005] of node;
n,m,i,j,k,maxn:longint;
procedure msort(l,r:longint);
var
i,j,k,mid:longint;
begin
mid:=(l+r)>>1;
if (l0) do
begin
if (y and 1=1) then res:=res*x mod p;
x:=x*x mod p;
y:=y>>1;
end;
exit(res);
end;
procedure prepare;
var
i:longint;
begin
fac[0]:=1;
for i:=1 to maxn do fac[i]:=fac[i-1]*i mod p;
inv[maxn]:=qpow(fac[maxn],p-2);
for i:=maxn-1 downto 0 do inv[i]:=inv[i+1]*(i+1) mod p;
end;
function combination(n,m:int64):int64;
begin
if (n
曲终,继续努力,备战CSP2019。