B: 怎样学习哲学
时间限制: 1 Sec 内存限制: 128 MB题目描述
OI大师抖儿在夺得银牌之后,顺利保送pku。这一天,抖儿问长者:“
虽然我已经保送了,但是我还要参加学考。马上就要考政治了,请问应该怎样学习哲学,通过政治考试?
”
长者回答:“你啊,Too Young Too Simple,Sometimes Naive! 哲学这种东西,不是说想懂就能懂的,需要静心撕烤。你去后面的森林里好好想想。 ”
长者回答:“你啊,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]*j到i的方案数。其中j是所有在i左上方的空点。
从起点到另一点的方案数,
显然答案是
C(
n,m
)。
由于模数是个较小的质数,可以套用
lucas
定理。
注意线性求逆元。
但是起始点和终止点都是不确定的,不难发现,其实相当于强制起始点在(0,0),终止点在(n+1,m+1)
#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]);
}