怎样学习哲学

来源:互联网 发布:java的socket 编辑:程序博客网 时间:2024/05/16 07:46

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

样例输入
3 5 2 2 3 3 4
样例输出
5
提示
【样例1说明】
方案一:选(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≤10^9,p≤min(n*m,2000)

【后记】

在经历了长久的撕烤之后,抖儿终于领悟了哲♂学奥义。
抖儿对长者说:“我知道了!哲学源于生活,只有撕烤生活,才能领悟哲理。”

这题没给部分分(原来是有的,题面里删了,这里不作讨论)

关于100%

  • 由题易知,x2>x1,y2>y1,则从(x1,y1)到(x2,y2)的方案数为C(y2-y1-1,x2-x1-1)。
  • 要到达终点不经过任何一个空点,不妨设每个空点(包括终点)都是一个关键点,则每种方案都只能到达一个关键点,然后自然推出状态dp[i]为经过关键点i的方案数。
  • 但是,起点是第一行任意点,重点是最后一行任意点,可设起点为(0,0),终点为(n+1,m+1)。
  • dp[i]的初始状态自然为C(yi-1,xi-1),然后排除经过其它关键点的情况,即减去所有在i左上方的的dp[j]*(关键点j到关键点i的方案数)。
  • 最后得dp[i]=C(yi-1,xi-1)-dp[j]*C(yi-yj-1,xi-xj-1),xi>xj,yi>yj

关于C(m,n)

  • 可参考Lucas定理,即C(m,n)=C(m%p,n%p)*C(m/p,n/p)
#include<iostream>#include<cstdio>#include<algorithm>#define MOD 1000003using namespace std;int n,m,p;long long dp[2010],ny[1000004],jc[1000004];struct node{    int x,y;} a[2010];bool cmp(node xx,node yy){    return(xx.x<yy.x||(xx.x==yy.x&&xx.y<yy.y));}long long C(int n,int m){    int t=(int)(jc[n]*jc[m-n]%MOD);    return jc[m]*ny[t]%MOD;}long long lucas(int x,int y){    if(x>y) return 0;    if(x<MOD&&y<MOD) return C(x,y);    return lucas(x/MOD,y/MOD)*lucas(x%MOD,y%MOD)%MOD;}long long dfs(int x){    if (dp[x]!=0) return dp[x];    dp[x]=lucas(a[x].x-1,a[x].y-1);    for (int i=1;i<x;i++)        if (a[i].x<a[x].x&&a[i].y<a[x].y)            dp[x]=(dp[x]-(dfs(i)*lucas(a[x].x-a[i].x-1,a[x].y-a[i].y-1))%MOD+MOD)%MOD;    return dp[x];}int main(){    scanf("%d%d%d",&n,&m,&p);    for (int i=1;i<=p;i++) scanf("%d%d",&a[i].x,&a[i].y);    sort(a+1,a+p+1,cmp);    jc[0]=jc[1]=1;ny[0]=ny[1]=1;    for (int i=2;i<MOD;i++) jc[i]=jc[i-1]*i%MOD,ny[i]=ny[MOD%i]*(MOD-MOD/i)%MOD;    a[++p]={n+1,m+1};    for (int i=1;i<=p;i++){        dp[i]=lucas(a[i].x-1,a[i].y-1);        for (int j=1;j<i;j++)            if (a[j].x<a[i].x&&a[j].y<a[i].y)                dp[i]=(dp[i]-dp[j]*lucas(a[i].x-a[j].x-1,a[i].y-a[j].y-1)%MOD+MOD)%MOD;    }    cout<<dp[p]<<endl;    return 0;}
2 0
原创粉丝点击