怎样学习哲学

B: 怎样学习哲学

时间限制: 1 Sec   内存限制: 128 MB

题目描述

OI大师抖儿在夺得银牌之后,顺利保送pku。这一天,抖儿问长者:“ 虽然我已经保送了,但是我还要参加学考。马上就要考政治了,请问应该怎样学习哲学,通过政治考试?
  长者回答:“你啊,Too Young Too Simple,Sometimes Naive! 哲学这种东西,不是说想懂就能懂的,需要静心撕烤。你去后面的森林里好好想想。
长者的后院有一片哲♂学森林。由于一些奥妙重重的原因,这片森林构成了一个n*m的矩形,其中每个点就代表了一棵树。此外,由于辣鸡出题人 KJDH 从中捣鬼,有些树被连根拔起(也就是消失了)。抖儿每天都要到树下撕烤,因此他想要在每一行选择一棵树。但是他非常讨厌走回头路,因此第i行选择的树必须比第i-1行的靠右。现在抖儿想知道,总共有多少种选择的方案。

输入

第一行三个整数n,m,p,分别表示森林的长、宽,以及消失的树的数目。
接下来p行每行两个整数,表示第a i 行第b i 列的树消失了。

输出

一行一个整数,表示方案数。由于答案可能很大,请对1000003取模。

样例输入

3 5 2
2 3
3 4

样例输出

5

提示

【样例说明】

方案一:选(1,1)(2,2)(3,3)

方案二:选(1,1)(2,2)(3,5)

方案三:选(1,1)(2,4)(3,5)

方案四:选(1,2)(2,4)(3,5)

方案五:选(1,3)(2,4)(3,5)

【限制与约定】


测试点编号

n,m

p

1

 

n,m≤10

 

 

2

3

4

5

 

n,m≤100

 

6

7

8

9

n,m≤5000

10

11

 

n,m≤100000

 

n,m≤100000

p=0

12

13

 

14

15

n,m≤10 9

p=0

16

17

 

18

19

20

对于所有的数据,保证 n,m≤10 9 ,p≤min(n*m,2000)

【后记】

在经历了长久的撕烤之后,抖儿终于领悟了哲♂学奥义。

抖儿对长者说:“我知道了!哲学源于生活,只有撕烤生活,才能领悟哲理。”

长者嘿嘿一笑:“你想多了。因为你在哲♂学之森中待的时间太长,政治学考已经在一个月前结束了。”

正解
dp[i]表示仅经过i这个空点的方案总数。
那么dp[i]=起始点到i的方案数-dp[j]*ji的方案数。其中j是所有在i左上方的空点。
从起点到另一点的方案数, 显然答案是 C( n,m )。 由于模数是个较小的质数,可以套用 lucas 定理。 注意线性求逆元。
但是起始点和终止点都是不确定的,不难发现,其实相当于强制起始点在(0,0),终止点在(n+1,m+1)
Code:
#include<cstdio> 
#include<algorithm> 
#include<cstring> 
using namespace std; 
typedef long long ll; 
const int mod=1000003; 
int n,m,q,i,j; 
ll dp[2010],mi[1000010],inv[1000010]; 
struct node{int x,y;}a[2010]; 
bool cmp(node x,node y){return x.x<y.x;} 
ll c(int n,int m){ 
    if (n<m)return 0; 
    if (n<mod)return mi[n]*inv[m]%mod*inv[n-m]%mod; 
        else return c(n/mod,m/mod)*c(n%mod,m%mod)%mod; 
} 
int main(){ 
    mi[0]=1;for (i=1;i<mod;i++)mi[i]=mi[i-1]*i%mod; 
    inv[1]=1;for (i=2;i<mod;i++)inv[i]=inv[mod%i]*(mod-mod/i)%mod; 
    inv[0]=1;for (i=1;i<mod;i++)(inv[i]*=inv[i-1])%=mod; 
    scanf("%d%d%d",&n,&m,&q); 
    for (i=1;i<=q;i++)scanf("%d%d",&a[i].x,&a[i].y); 
    q++;a[q].x=n+1;a[q].y=m+1; 
    sort(a+1,a+q+1,cmp); 
    for (i=1;i<=q;i++){ 
        dp[i]=c(a[i].y-1,a[i].x-1); 
        for (j=1;j<i;j++) 
            if (a[i].x>a[j].x&&a[i].y>a[j].y)dp[i]=(dp[i]-dp[j]*c(a[i].y-a[j].y-1,a[i].x-a[j].x-1)%mod+mod)%mod; 
    } 
    printf("%lld\n",dp[q]); 
} 

猜你喜欢

转载自blog.csdn.net/qq_34531807/article/details/78004670
今日推荐