bzoj3907 网格 & bzoj2822 [AHOI2012]树屋阶梯——卡特兰数+高精度

题目:bzoj3907:https://www.lydsy.com/JudgeOnline/problem.php?id=3907

bzoj2822:https://www.lydsy.com/JudgeOnline/problem.php?id=2822

 

bzoj3907:

从网格图的角度很好想啊,就是像定义一样,一下子就出来了 ans = C(n+m,n) - C(n+m,m-1);

那么从01串的角度呢?这个是0和1的个数不同的问题呢...

看到这篇博客:https://blog.csdn.net/u014097230/article/details/44244793

里面有很多很好的小例子!其中的 hdu 1133,不正可以转化成这道题吗!

于是就解决了,得到的答案和上面那种方法得到的一样:ans = C(n+m,n) - C(n+m,m-1);

然而难道是卡特兰数的题都太容易写了,所以非得来个高精度?!一时间不想做了...

直到看到了这篇博客:https://www.cnblogs.com/Tunix/p/4354348.html

怎么会有这么优美的高精度求组合数写法!!!顿时有了信心,马上抄了一遍成功写好了!

我会牢牢记住这篇美丽的高精度的(话说好像还是第一次写高精度求组合数啊)。

bzoj2822:就是求卡特兰数第 n 项,因为正好符合了那个递推式;

也要高精度,就用同一个板子A了(令 m = n 就好啦)。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
int const maxn=10005,mod=1e8;
int n,m,pri[maxn],mn[maxn],cnt,p[maxn];
ll a[1005],b[1005];
void init()
{
    mn[1]=1;
    for(int i=2;i<=n+m;i++)
    {
        if(!mn[i])pri[++cnt]=i,mn[i]=i;
        for(int j=1;j<=cnt&&i*pri[j]<=n+m;j++)
        {
            mn[i*pri[j]]=pri[j];
            if(i%pri[j]==0)break;
        }
    }
}
ll pw(int a,int b)
{
    ll ret=1;
    for(;b;b>>=1,a*=a)
        if(b&1)ret*=a;
    return ret;
}
void mul(ll a[],ll k)
{
    ll x=0;
    for(int i=1;i<=a[0];i++)
    {
        a[i]=a[i]*k+x;
        x=a[i]/mod;
        a[i]%=mod;
    }
    while(x)a[++a[0]]+=x%mod,x/=mod;
}
void getc(ll a[],int n,int m)
{
    memset(p,0,sizeof p);
    for(int i=2;i<=n;i++)p[i]++;
    for(int i=2;i<=m;i++)p[i]--;
    for(int i=2;i<=n-m;i++)p[i]--;
    for(int i=n;i>=2;i--)
    {
        if(mn[i]==i) mul(a,pw(i,p[i]));
        else p[mn[i]]+=p[i],p[i/mn[i]]+=p[i];//转化到质因子上!太妙了! 
    }
}
void dec(ll a[],ll b[])
{
    for(int i=1;i<=a[0];i++)
    {
        if(a[i]<b[i])a[i]+=mod,a[i+1]--;
        a[i]-=b[i];
    }
    while(a[0]&&!a[a[0]])a[0]--;
}
void print(ll a[])
{
    printf("%lld",a[a[0]]);
    for(int i=a[0]-1;i;i--)
        printf("%08lld",a[i]);
    printf("\n");
}
int main()
{
    scanf("%d%d",&n,&m);
    init();
    a[0]=a[1]=b[0]=b[1]=1;
    getc(a,n+m,n);
    getc(b,n+m,m-1);
    dec(a,b);
    print(a);
    return 0;
}
posted @ 2018-07-04 17:22  Zinn  阅读(203)  评论(0编辑  收藏  举报