题目概述
n
行
解题报告
哇,最近考到这道题,考试时完全不会做啊,考完后发现很水啊Orz。
朴素的障碍物过河卒问题直接刷递推,效率是
先将障碍物排序,定义
首先到第
i
个障碍物方案总数为
由于这道题与大素数取模,所以我们预处理出所有阶乘的逆元就可以快速求出组合数,下面介绍一下线性的预处理:
1. 先用逆元公式
INV[i]=−⌊pi⌋∗INV[p mod i]
算出
i
的逆元。
2. 很显然
示例程序
#include<cstdio>
#include<algorithm>
using namespace std;
#define fi first
#define se second
#define mp make_pair
typedef long long LL;
typedef pair<int,int> pii;
const int maxn=100000,maxm=100000,maxk=2000,MOD=1000000007;
int n,m,K,fac[maxn+maxm+5],INV[maxn+maxm+5],f[maxk+5];
pii a[maxk+5];
inline bool Eoln(char ch) {return ch==10||ch==13||ch==EOF;}
inline char readc()
{
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
if (l==r) return EOF; else return *l++;
}
inline int readi(int &x)
{
int tot=0,f=1;char ch=readc(),lst='+';
while ('9'<ch||ch<'0') {if (ch==EOF) return EOF;lst=ch;ch=readc();}
if (lst=='-') f=-f;
while ('0'<=ch&&ch<='9') tot=tot*10+ch-48,ch=readc();
return x=tot*f,Eoln(ch);
}
void First_make()
{
fac[0]=1;for (int i=1;i<=n+m;i++) fac[i]=(LL)fac[i-1]*i%MOD;
INV[0]=INV[1]=1;for (int i=2;i<=n+m;i++) INV[i]=(LL)(MOD-MOD/i)*INV[MOD%i]%MOD;
for (int i=1;i<=n+m;i++) INV[i]=(LL)INV[i-1]*INV[i]%MOD;
}
int C(int x,int y) {return (LL)fac[y]*INV[x]%MOD*INV[y-x]%MOD;}
int Sum(int i,int j) {return C(a[j].fi-a[i].fi,a[j].fi-a[i].fi+a[j].se-a[i].se);}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
readi(n);readi(m);readi(K);First_make();a[0]=mp(1,1);
for (int i=1;i<=K;i++) readi(a[i].fi),readi(a[i].se);
a[++K]=mp(n,m);sort(a+1,a+1+K);
for (int i=1;i<=K;i++)
{
f[i]=Sum(0,i);
for (int j=1;j<=i-1;j++) if (a[j].se<=a[i].se)
f[i]=(f[i]-(LL)f[j]*Sum(j,i)%MOD+MOD)%MOD;
}
return printf("%d\n",f[K]),0;
}