题意
给你一个n*n的地图,让你从(0,0)走到(n,n),且到了对角线时只能走(x+1,x),而且不能走到障碍物里(有c个),问你走的方案数。(mod 109+7 )
数据范围
对于30%的数据,保证N<=5000
对于另外20%的数据,保证C=0
对于另外20%的数据,保证C=1
对于100%的数据,保证N<=100000,C<=1000
保证对于(0,0),(N,N)不存在障碍点。
分析
对角线
这道题其实很像【GDOI2015】Hearth Stone。。。
我们可以分类讨论:
我们可以讨论一下我们违法的方案,且这个违法的方案是走对角线的。
这是一张神奇的图。(转自Philipsweng)
粉色的那条直线是不能走的,那么我们可以把触碰到粉线的方案对称到另一边,所以我们可以把走到终点的方案对称到对应点,求到对应点的方案数即可。
经过其它的障碍点
我们可以从c入手,我们发现c很小,所以是否是根据c去做呢?
事实就是这样的。
类似容斥原理(补集的思想)
我们可以用类似容斥原理的思想去想。
走到第i个点的不走其他的障碍点的方案数=走到第i个障碍点可以从无限制走到第i个障碍点的方案数-走时可以走一些障碍点的方案数。
但若是我们不能直接去计算,直接转移,因为这样是毫无顺序的,也就是说我们会算到一些重复的方案。
所以:
我们设一个f[i],表示我们从(0,0)走到第i个障碍点的除当前点的方案。g[i]表示我们从(0,0)走到第i个障碍点可以经过一些障碍点。那么转移为:
g[i]=∑j=1i−1f[j]∗ways(pj,pi)
(pi表示第i个障碍点的坐标,
ways(x,y)
,表示我们从第x个关键点走到第y个关键点的不经过对角线的方案数)
然而我们可以很轻松的算出
ways(x1,y1,x2,y2)
.
我们设
s1=(x2−x1),s2=(y2−y1);那么ways(x1,y1,x2,y2)=C(s2s2+s1)
。
至于为什么g可以这样求呢,因为:
我们设一条路径是这样的
(p1,p2,p3,p4,..pi)
那么我们只用限制于是否走第j个点,那么后面的点是可以随便走的,这样我们便可以保证我们的统计是对的了(每一次统计走的都不是同一个点,也就是说我们强制它先只走一个点,所以这是不会重复的,是有序的)。
而最后只要把终点加进障碍点即可。
答案便是
ways(0,0,n,n)−g[c+1]
最终的复杂度为 O(c2) ,很好的解决了这个问题。
代码:
当然我打这道题用了大约一个下午原因是因为我脑残打多了一个符号。。
const mo=1000000007;
var
n,m,s,t,i,j:longint;w:int64;
x:array[0..100000,1..2] of longint;
fac,pop:array[0..300005] of int64;
f,g:array[1..100000] of int64;
function get(y,x:longint):int64;
begin
if x=1 then exit(y)
else begin
get:=get(y,x div 2);
get:=(get*get)mod mo;
if x mod 2<>0 then get:=(get*y)mod mo;
end;
end;
procedure qsort(l,r:longint);
var i,j,mid,mie:longint;
begin
i:=l;j:=r;mid:=x[(l+r)shr 1,1];mie:=x[(l+r)shr 1,2];
repeat
while (x[i,1]<mid)or(x[i,1]=mid)and(x[i,2]<mie) do inc(i);
while (x[j,1]>mid)or(x[j,1]=mid)and(x[j,2]>mie) do dec(j);
if i<=j then begin x[0]:=x[i];x[i]:=x[j];x[j]:=x[0];inc(i);dec(j);end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end;
function ways(l,r,s,t:longint):int64; var s1,t1,su1,pe:int64;
begin
s1:=t-1;t1:=s+1;
if (l>s1)or(r>t1) then su1:=0 else
if (s1=l)or(t1=r) then su1:=1 else begin
s1:=s1-l;t1:=t1-r;su1:=((fac[s1+t1]*((pop[s1]*pop[t1])mod mo))mod mo);
end;
if (l>s)or(r>t) then pe:=0 else
if (s=l)or(t=r) then pe:=1 else begin
s:=s-l;t:=t-r;pe:=(fac[s+t]*((pop[s]*pop[t])mod mo))mod mo;end;
exit((pe-su1+mo)mod mo);
end;
begin
readln(n,m);
fac[0]:=1;
for i:=1 to 3*n do begin fac[i]:=(fac[i-1]*i)mod mo;pop[i]:=get(fac[i],mo-2);end;
for i:=1 to m do read(x[i,1],x[i,2]);
if m=0 then begin
writeln(ways(0,0,n,n)mod mo);
end else begin inc(m);x[m,1]:=n;x[m,2]:=n;
qsort(1,m);
f[1]:=ways(0,0,x[1,1],x[1,2]);
for i:=2 to m do begin
for j:=1 to i-1 do if x[j,2]<=x[i,2] then begin
w:=ways(x[j,1],x[j,2],x[i,1],x[i,2]);
g[i]:=(g[i]+(f[j]*w)mod mo)mod mo;
end;
w:=ways(0,0,x[i,1],x[i,2]);
f[i]:=(w-g[i]+mo)mod mo;
end;
writeln(f[m]);
end;
end.