原题链接:路径计数2 - 题目 - Daimayuan Online Judge
解题思路:按照题目中两种移动方式,从一个点移动到另一个点的路径数可以用组合数公式快速计算得出。如果从点(0,0)移动到点(n,m),一共需要走n+m步,其中n步为向下。那么在n+m步中选择n步,得到的结果就是在不同步数下选择的向下移动,即路径数。
而题目中有一些不可通行的点,那么就要在总路径数中减去到达这些点的路径数。而不可通行的点之间,也有一些重复路径,那么也需要将重复的路径减掉。这两步的操作是一样的,因为减去重复路径,等同于减去所有到达其他点再出发到达该点的路径。
然后减去包含的点只需要先对存储点的数组进行排序,越靠近(0,0)的在前面。然后只需要O(n^2)的复杂度就可以减去重复路径了。
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define mod 1000000007
long long fact[10000010],inv[10000010];//fact存阶乘,inv存对应逆元
long long n,m,sum[1000010];//sum为到达不同点的不重复路径数
struct qwq{//存点
long long x,y;
} p[1000010];
long long int_pow(long long x,long long k){//快速幂
long long ans=1 ;
while(k){
if(k&1) ans=ans*x%mod;
k=k>>1;
x=(x*x)%mod;
}
return ans ;
}
void pre_work(){//预处理阶乘与逆元
fact[0]=1;
fact[1]=1;
for(long long i=2;i<=10000000;i++) fact[i]=fact[i-1]*i,fact[i]%=mod;
inv[10000000]=int_pow(fact[10000000],mod-2);
for(long long i=9999999;i>0;i--) inv[i]=inv[i+1]*(i+1)%mod;
inv[0]=1;
return;
}
int cmp(qwq a,qwq b) {//sort排序的判断函数
return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
int main(){
pre_work();
cin>>n>>m;//输入
for(int i=0;i<m;i++){
cin>>p[i].x>>p[i].y;
}
p[m].x=n;//把重点也作为不可通行点处理
p[m].y=n;
m++;
sort(p,p+m,cmp);//排序
long long x1,y1,x2,y2;//缓存数据,防止重复计算
for(int i=0;i<m;i++){//遍历每个不可通行点
x1=p[i].x-1;
y1= p[i].y-1;
sum[i]=fact[x1+y1]*inv[x1]%mod*inv[y1]%mod;//组合数公式计算没有其他点干扰的路径数
for(int j=0;j<i;j++) {//查是否有重复路径
if(p[j].x<=p[i].x&&p[j].y<=p[i].y) {//如果有则减去通过那些点的路径
x2=x1-p[j].x+1;
y2=y1-p[j].y+1;
sum[i]=(sum[i]-fact[x2+y2]*inv[x2]%mod*inv[y2]%mod*sum[j]%mod)%mod;
if(sum[i]<=0) sum[i]=(sum[i]+mod)%mod;
}
}
}
cout<<sum[m-1];
return 0;
}