版权声明:LeoJAM Presents https://blog.csdn.net/fcb_x/article/details/82830411
OI大师抖儿在夺得银牌之后,顺利保送PKU。这一天,抖儿问长者:“虽然我已经保送了,但是我还要参加学考。马上就要考政治了,请问应该怎样学习哲学,通过政治考试?”
长者回答:“你啊,Too Young Too Simple,Sometimes Naive!哲学这种东西,不是说想懂就能懂的,需要静心撕烤。你去后面的森林里好好想想。”
长者的后院有一片哲♂学森林。由于一些奥妙重重的原因,这片森林构成了一个n*m的矩形,其中每个点就代表了一棵树。此外,由于辣鸡出题人小C从中捣鬼,有些树被连根拔起(也就是消失了)。抖儿每天都要到树下思考,因此他想要在每一行选择一棵树。但是他非常讨厌走回头路,因此第i行选择的树必须比第i-1行的靠右。现在抖儿想知道,总共有多少种选择的方案。
这个是一样的:但是注意干涉点的特殊性
所以设为X-1,Y-1
这样下一步必然走干涉点
然后同理DP
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
typedef int INT;
#define int long long
const int N=2010;
const int mod=1000003;
inline int Quick_Pow(int x,int k){
int ret=1;
while(k){
if(k%2){
ret=ret*x%mod;
}
k/=2;
x=x*x%mod;
}
return ret;
}
struct Node{
int x,y;
}A[N];
int fac[mod+1];
int inv[mod+1];
int n,m,q;
int G[2010][2010];
int F[2010];
bool cmp(Node A,Node B){
return A.y<B.y||(A.y==B.y&&A.x<B.x);
}
void Pre(){
fac[0]=1;
for(int i=1;i<mod;++i){
fac[i]=fac[i-1]*i%mod;
}
inv[mod-1]=Quick_Pow(fac[mod-1],mod-2);
for(int i=mod-2;i>=0;--i){
inv[i]=inv[i+1]*(i+1)%mod;
}
}
int C(int n,int m){
if(m>n)return 0;
return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int Lucas(int n,int m){
if(!m)return 1;
return Lucas(n/mod,m/mod)*C(n%mod,m%mod)%mod;
}
void Build(){
for(int i=0;i<=q;++i){
for(int j=i+1;j<=q;++j){
if(A[j].x>A[i].x&&A[j].y>A[i].y)
G[i][j]=Lucas(A[j].y-A[i].y-1,A[j].x-A[i].x-1);
}
}
}
INT main(){
Pre();
scanf("%lld%lld%lld",&n,&m,&q);
for(int i=1;i<=q;++i){
scanf("%lld%lld",&A[i].x,&A[i].y);
}
q++;
A[0].x=0;
A[0].y=0;
A[q].x=n+1;
A[q].y=m+1;
sort(A+1,A+1+q,cmp);
Build();
for(int i=1;i<=q;++i){
F[i]=G[0][i];
for(int j=1;j<i;++j){
if(A[i].x>A[j].x&&A[i].y>A[j].y)
F[i]=((F[i]-G[j][i]*F[j]%mod)+mod)%mod;
}
// cout<<F[i]<<" ";
}
// cout<<G[2][3];
cout<<F[q];
}