[容斥][dp][卡特兰数]登山

来源:互联网 发布:python关闭网页 编辑:程序博客网 时间:2024/06/05 20:26

这里写图片描述
这里写图片描述

这里写图片描述

sol:显然是dp容斥+卡特兰数。
卡特兰数是用来求点之间路径的条数的。
然后容斥dp,用f[i]表示只经过i这个障碍点的方案数。
那么
f[i]=f[j]*way(j,i)
f[i]=way(源点,i)-f[i]

最后我们加入n,n,答案就在里面。

#include<cstdio>#include<algorithm>#include<string>#include<cstring>#include<cstdlib>#include<cmath>#include<iostream>using namespace std;typedef long long ll;const int pyz=1e9+7;int n,m;inline int read(){    char c;    int res,flag=0;    while((c=getchar())>'9'||c<'0') if(c=='-')flag=1;    res=c-'0';    while((c=getchar())>='0'&&c<='9') res=(res<<3)+(res<<1)+c-'0';    return flag?-res:res;}const int M=210000;struct cc{    int x,y;}q[M];inline bool cmp(const cc &a,const cc &b){    return (a.x<b.x)||(a.x==b.x&&a.y<b.y);}int ksm(int s,int t){    int res=1;    while(t)    {        if(t&1) res=(ll)res*s%pyz;        s=(ll)s*s%pyz;        t>>=1;    }    return res;}int fac[M],inv[M];inline int C(int n,int m){    return (ll)fac[n]*inv[m]%pyz*inv[n-m]%pyz;}inline void spit(int &x){    x=(x%pyz+pyz)%pyz;}inline int way(int x1,int y1,int x2,int y2)//从x1,y1走到x2,y2 {    if(y1>y2) return 0;    int x3=y2-1,y3=x2+1;    int tmp=C(x2+y2-x1-y1,x2-x1);    if(y1>y3||x1>x3) return tmp;    tmp=tmp-C(x3+y3-x1-y1,x3-x1);    spit(tmp);    return tmp;}int dn;int f[M];int main(){    freopen("walk.in","r",stdin);    freopen("walk.out","w",stdout);    n=read();    m=read();    for(int i=1;i<=m;++i)    {        q[i].x=read();        q[i].y=read();    }    ++m;    q[m].x=n;    q[m].y=n;    sort(q+1,q+1+m,cmp);    dn=n<<1;    fac[0]=inv[0]=1;    for(int i=1;i<=dn;++i) fac[i]=(ll)fac[i-1]*i%pyz;    inv[dn]=ksm(fac[dn],pyz-2);    for(int i=dn-1;i>=1;--i) inv[i]=(ll)inv[i+1]*(i+1)%pyz;    for(int i=1;i<=m;++i)    {        for(int j=1;j<i;++j)        f[i]=(f[i]+(ll)f[j]*way(q[j].x,q[j].y,q[i].x,q[i].y)%pyz)%pyz;        f[i]=way(0,0,q[i].x,q[i].y)-f[i];        spit(f[i]);    }    printf("%d",f[m]);}
原创粉丝点击