省选专练之容斥怎样学习哲学

版权声明: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];
}

猜你喜欢

转载自blog.csdn.net/fcb_x/article/details/82830411