[入门OJ3876]怎样学习哲学

题目大意:
  有一个$n\times m(n,m\leq 10^9)$的网格图,从一个点可以到下一行中列数比它大的点。有$k(k\leq 2000)$个点是不能走的,问从第$1$行到第$n$行共有几种方案。

思路:
  动态规划求出以点$i$为终点的方案数,直接$O(nm)$推显然会超时,因此我们$O(k)$可以对于每个障碍点求出组合数。组合数可以用Lucas定理求。
  Lucas定理:$\binom{n}{m}\mod p=\binom{\lfloor\frac{n}{p}\rfloor}{\lfloor\frac{m}{p}\rfloor}\binom{n\mod p}{m\mod p}\mod p$。

 1 #include<cstdio>
 2 #include<cctype>
 3 #include<vector>
 4 #include<algorithm>
 5 typedef long long int64;
 6 inline int getint() {
 7     register char ch;
 8     while(!isdigit(ch=getchar()));
 9     register int x=ch^'0';
10     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
11     return x;
12 }
13 const int mod=1000003,K=2001;
14 int fact[mod],factinv[mod],f[K];
15 std::pair<int,int> v[K];
16 void exgcd(const int &a,const int &b,int &x,int &y) {
17     if(!b) {
18         x=1;
19         y=0;
20         return;
21     }
22     exgcd(b,a%b,y,x);
23     y-=a/b*x;
24 }
25 inline int inv(const int &x) {
26     int ret,tmp;
27     exgcd(x,mod,ret,tmp);
28     return (ret%mod+mod)%mod;
29 }
30 int lucas(const int &n,const int &m) {
31     if(n<m) return 0;
32     if(n<mod&&m<mod) return (int64)fact[n]*factinv[m]%mod*factinv[n-m]%mod;
33     return (int64)lucas(n/mod,m/mod)*lucas(n%mod,m%mod)%mod;
34 }
35 int main() {
36     fact[0]=1;
37     for(register int i=1;i<mod;i++) {
38         fact[i]=(int64)fact[i-1]*i%mod;
39     }
40     factinv[mod-1]=inv(fact[mod-1]);
41     for(register int i=mod-2;~i;i--) {
42         factinv[i]=(int64)factinv[i+1]*(i+1)%mod;
43     }
44     const int n=getint(),m=getint(),k=getint();
45     for(register int i=0;i<k;i++) {
46         const int x=getint(),y=getint();
47         v[i]=std::make_pair(x,y);
48     }
49     std::sort(&v[0],&v[k]);
50     v[k]=std::make_pair(n+1,m+1);
51     for(register int i=0;i<=k;i++) {
52         f[i]=lucas(v[i].second-1,v[i].first-1);
53         for(register int j=0;j<i;j++) {
54             if(v[i].first<=v[j].first||v[i].second<=v[j].second) continue;
55             f[i]=((f[i]-(int64)f[j]*lucas(v[i].second-v[j].second-1,v[i].first-v[j].first-1))%mod+mod)%mod;
56         }
57     }
58     printf("%d\n",f[k]);
59     return 0;
60 }

 

posted @ 2018-01-10 13:41  skylee03  阅读(133)  评论(0编辑  收藏  举报