【算法】卢卡斯定理
【问题描述】
OI大师抖儿在夺得银牌之后,顺利保送pku。这一天,抖儿问长者:“虽然我已经保送了,但是我还要参加学考。马上就要考政治了,请问应该怎样学习哲学,通过政治考试?”
长者回答:“你啊,Too
Young Too Simple,Sometimes Naive!哲学这种东西,不是说想懂就能懂的,需要静心撕烤。你去后面的森林里好好想想。”
长者的后院有一片哲♂学森林。由于一些奥妙重重的原因,这片森林构成了一个n*m的矩形,其中每个点就代表了一棵树。此外,由于辣鸡出题人KJDH从中捣鬼,有些树被连根拔起(也就是消失了)。抖儿每天都要到树下撕烤,因此他想要在每一行选择一棵树。但是他非常讨厌走回头路,因此第i行选择的树必须比第i-1行的靠右。现在抖儿想知道,总共有多少种选择的方案。
【输入格式】
第一行三个整数n,m,p,分别表示森林的长、宽,以及消失的树的数目。
接下来p行每行两个整数,表示第ai行第bi列的树消失了。
p<=2000 n,m<=10^9
【输出格式】
一行一个整数,表示方案数。由于答案可能很大,请对1000003取模。
【题解】
C(n,m)%p=C(n%p,M%p)*C(n/p,m/p)%p
显然向下x个单位,向右y个方案是C(x-1,y-1)
f[i]只到第i个点的方案数
f[i]=C(x[i]-1,y[i]-1)-sigma(f[j]*C(x[i]-x[j]-1,y[i]-y[j]-1))(y[i]>=y[j]&&x[i]>=x[j]&&i>j)
#include<stdio.h> #include<stdlib.h> #include<iostream> #include<string> #include<string.h> #include<algorithm> #include<math.h> #include<queue> #include<map> #include<vector> #include<set> #define il inline #define re register #define mod 1000003 using namespace std; typedef long long ll; const int N=2016; int n,a[1100000],r[1100000],m,p,f[N]; struct data{int x,y;} t[N]; il bool cmp(data a,data b){ return a.x<b.x; } il int C(int n,int m){ if(n<m) return 0; if(n<mod) return 1ll*a[n]*r[m]*r[n-m]%mod; return 1ll*C(n/mod,m/mod)*C(n%mod,m%mod)%mod; } int main(){ freopen("zhexue.in","r",stdin); freopen("zhexue.out","w",stdout); a[0]=1;r[1]=1;r[0]=1; for(int i=1;i<mod;i++) a[i]=1ll*a[i-1]*i%mod; for(int i=2;i<mod;i++) r[i]=1ll*r[mod%i]*(mod-mod/i)%mod; for(int i=1;i<mod;i++) r[i]=1ll*r[i]*r[i-1]%mod; scanf("%d%d%d",&n,&m,&p); for(int i=1;i<=p;i++) scanf("%d%d",&t[i].x,&t[i].y); t[++p].x=n+1;t[p].y=m+1; sort(t+1,t+p+1,cmp); for(int i=1;i<=p;i++){ f[i]=C(t[i].y-1,t[i].x-1); //cout<<f[i]<<endl; for(int j=1;j<i;j++) if(t[j].x<t[i].x&&t[j].y<t[i].y){ f[i]=((f[i]-1ll*f[j]*C(t[i].y-t[j].y-1,t[i].x-t[j].x-1)%mod)%mod+mod)%mod; } } cout<<f[p]; return 0; }
蜉蝣渴望着飞翔,尽管黄昏将至