• 高精+卡特兰数 bzoj3907网格


    问题 A: 网格
    时间限制: 1 Sec 内存限制: 256 MB
    题目描述
    【问题描述】
    某城市的街道呈网格状,左下角坐标为A(0, 0),右上角坐标为B(n, m),其中n >= m。现在从A(0, 0)点出发,只能沿着街道向正右方或者正上方行走,且不能经过图示中直线左上方的点,即任何途径的点(x, y)都要满足x >= y,请问在这些前提下,到达B(n, m)有多少种走法。
    【输入格式】
    输入文件中仅有一行,包含两个整数n和m,表示城市街区的规模。
    【输出格式】
    输出文件中仅有一个整数和一个换行/回车符,表示不同的方案总数。
    【输入样例1】
    6 6
    【输出样例1】
    132
    【输入样例2】
    5 3
    【输出样例2】
    28
    【数据范围】
    50%的数据中,n = m,
    在另外的50%数据中,有30%的数据:1 <= m < n <= 100
    100%的数据中,1 <= m <= n <= 5 000

    结论就是C(n+m,n)-C(n+m,n+1)。
    貌似是卡特兰数的基本证明。。。请去度娘找证明,我不会。→_→
    剩下的只要搞一个高精即可。
    有大佬重载了高精除。。。我。。因为一定是整数,所以我把分子分母强行约分,然后只做乘法,貌似也行。

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<vector>
    #define N 50005
    #define inf 10000
    #define ll long long
    using namespace std;
    int read()
    {
        int sum=0,f=1;char x=getchar();
        while(x<'0'||x>'9'){if(x=='-')f=-1;x=getchar();}
        while(x>='0'&&x<='9'){sum=(sum<<1)+(sum<<3)+x-'0';x=getchar();}
        return sum*f;
    }
    int n,m;
    int gcd(int x,int y){return !y?x:gcd(y,x%y);}
    struct node
    {
        int f[10005],s;
        node(){s=0;memset(f,0,sizeof(f));}
        friend node const operator+(node a,node b)
        {
            if(b.s>a.s)swap(a,b);
            int i;
            for(i=1;i<=a.s;i++)
            {
                a.f[i]+=b.f[i];
                if(a.f[i]>=inf)
                {
                    a.f[i]-=inf;
                    a.f[i+1]++;
                }
            }
            if(a.f[a.s+1]>0)a.s++;
            return a;
        }
        friend node const operator-(node a,node b)
        {
            for(int i=1;i<=a.s;i++)
            {
                a.f[i]-=b.f[i];
                if(a.f[i]<0)
                {
                    a.f[i]+=inf;
                    a.f[i+1]--;
                }
            }
            while(a.f[a.s]==0)a.s--;
            return a;
        }
        friend node const operator*(node a,int b)
        {
            int x=0,i;
            for(i=1;i<=a.s;i++)
            {
                a.f[i]*=b;a.f[i]+=x;
                x=a.f[i]/inf;
                a.f[i]%=inf;
            }
            if(x!=0)
            {
                a.s=i;a.f[i]+=x;
            }
            return a;
        }
    };
    int vis[10005],v[10005];
    void hh(node x)
    {
        printf("%d",x.f[x.s]);
        for(int i=x.s-1;i>0;i--)
            printf("%04d",x.f[i]);
        printf("
    ");
    }
    void work()
    {
        node sum,cnt;
        sum.s=1;sum.f[1]=1;
        cnt.s=1;cnt.f[1]=1;
        for(int i=2;i<=n;i++)vis[i]=i;
        for(int i=m+1;i<=m+n;i++)
        {
            v[i]=i;
            for(int j=2;j<=n;j++)
                if(vis[j]!=1)
                {
                    int k=gcd(v[i],vis[j]);if(k==1)continue;
                    v[i]/=k;vis[j]/=k;
                    if(v[i]==1)break;
                }
        }
        for(int i=m+1;i<=m+n;i++)if(v[i]!=1)sum=sum*v[i];
        for(int i=2;i<=n+1;i++)vis[i]=i;
        for(int i=m;i<=m+n;i++)
        {
            v[i]=i;
            for(int j=2;j<=n+1;j++)
                if(vis[j]!=1)
                {
                    int k=gcd(v[i],vis[j]);if(k==1)continue;
                    v[i]/=k;vis[j]/=k;
                    if(v[i]==1)break;
                }
        }
        for(int i=m;i<=m+n;i++)if(v[i]!=1)cnt=cnt*v[i];
        cnt=sum-cnt;
        hh(cnt);
    }
    int main()
    {
        n=read();m=read();
        work();
    }
  • 相关阅读:
    AS3包类大全新手必学
    31天重构学习笔记27. 去除上帝类
    31天重构学习笔记26. 避免双重否定
    31天重构学习笔记29. 去除中间人对象
    与继承相关的一些重构(二)
    31天重构学习笔记28. 为布尔方法命名
    与继承相关的一些重构(一)
    31天重构学习笔记25. 引入契约式设计
    必会重构技巧(一):封装集合
    31天重构学习笔记30. 尽快返回
  • 原文地址:https://www.cnblogs.com/QTY2001/p/7632643.html
Copyright © 2020-2023  润新知