1. 程式人生 > >省選專練之容斥怎樣學習哲學

省選專練之容斥怎樣學習哲學

 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];
}