题目描述
恶梦是一个登山爱好者,今天他来到了黄山。
俗话说的好,不走回头路。所以在黄山,你只能往前走,或者往上走。并且很显然的是,当你走到山脊的时候,你不能够往上走,你只能往前走一步再往上走。
抽象一点而言就是,你可以把黄山视为一个N * N格点图,恶梦从(0,0)开始出发,要走到(N,N)。当他走到位置(x,y)的时候,它可以往(x + 1,y),或(x,y+1)走。
并且当他走到(x,x)的时候,由于他已经处在了山脊上,所以他不能够往(x,x+1)方向上走。
当恶梦兴致勃勃准备开始爬山的时候,他的同伴告诉他,黄山由于年久失修,有一些位置出现了大坑,不能走。恶梦觉得更刺激了,但他想先知道他能有多少种方式走到黄山顶。
由于这个数字很大,所以你只需要将答案对10^9 + 7取模输出即可。
对于30%的数据,保证N<=5000
对于另外20%的数据,保证C=0
对于另外20%的数据,保证C=1
对于100%的数据,保证N<=100000,C<=1000
保证对于(0,0),(N,N)不存在障碍点。
解题思路
如果没有山脊的限制就十分简单了嘛。
假如没有,设f[i]表示恰好走到第i个障碍点的合法路径条数,即除了这个点,路径其他点碰不到障碍。然后f[i]可以由能够到达他的障碍点j的f[j]容斥出来,即在不合法路径经过的第一个障碍点j处容斥掉不合法答案。
考虑有山脊的限制怎么办。实际上,我们如果要从(a,b)到达(c,d),不碰到直线到(c,d)的方案数=随便走到(c,d)的方案数-随便走到(c,d)关于直线的对称点的方案数。
可以发现,任意一条走到对称点的路径一定会碰到直线,其第一个碰到直线的点后面的路径对称回去,恰好一一对应不合法的到(c,d)的路径。
那么就很好算了。
代码
不是同一道题,不过大体一样,多了一些删去没用的障碍点的操作。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
typedef double db;
#define fo(i,j,k) for(i=j;i<=k;i++)
#define fd(i,j,k) for(i=j;i>=k;i--)
#define cmax(a,b) (a=(a>b)?a:b)
#define cmin(a,b) (a=(a<b)?a:b)
const int N=5e6+5,mo=1e9+7;
struct rec
{
int x,y;
};
bool operator <(rec a,rec b)
{
return a.x<b.x||a.x==b.x&&a.y<b.y;
}
multiset<rec> tr;
int fac[N],rev[N],i,j,n,m,t,C,X[3005],Y[3005],id[3005],f[3005],t1;
bool cmp(int x,int y)
{
return X[x]<X[y]||X[x]==X[y]&&Y[x]<Y[y];
}
int ksm(int x,int y)
{
int ret=1;
while (y)
{
if (y&1) ret=1ll*ret*x%mo;
y>>=1;
x=1ll*x*x%mo;
}
return ret;
}
void predo(int n)
{
fac[0]=1;
fo(i,1,n) fac[i]=1ll*i*fac[i-1]%mo;
rev[n]=ksm(fac[n],mo-2);
fd(i,n,1) rev[i-1]=1ll*i*rev[i]%mo;
}
int vert(int &x,int &y)
{
y--;x++;
swap(x,y);
}
int c(int n,int m)
{
if (n==m) return 1;
if (n>m||m<0||n<0) return 0;
return 1ll*fac[m]*rev[n]%mo*rev[m-n]%mo;
}
int ways(int ax,int ay,int bx,int by)
{
int ret=0;
ret=c(bx-ax,bx-ax+by-ay);
vert(bx,by);
ret=(ret-c(bx-ax,bx-ax+by-ay)+mo)%mo;
return ret;
}
int main()
{
scanf("%d %d",&n,&t1);
m=n;
predo(5e6);
fo(i,1,t1)
{
t++;
scanf("%d %d",X+t,Y+t);
if (X[t]<0||Y[t]>m||X[t]>n||Y[t]>X[t]||tr.find({X[t],Y[t]})!=tr.end()) t--;
else tr.insert({X[t],Y[t]});
}
t++;
X[t]=n;Y[t]=m;
fo(i,1,t) id[i]=i;
sort(id+1,id+1+t,cmp);
fo(i,1,t)
if (X[id[i]]>=0)
{
f[i]=ways(0,0,X[id[i]],Y[id[i]]);
fo(j,1,i-1) if (X[id[j]]>=0&&X[id[j]]<=X[id[i]]&&Y[id[j]]<=Y[id[i]])
f[i]=(f[i]-1ll*f[j]*ways(X[id[j]],Y[id[j]],X[id[i]],Y[id[i]])%mo+mo)%mo;
}
printf("%d\n",f[t]);
}