省選專練之容斥怎樣學習哲學
阿新 • • 發佈:2018-12-11
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]; }