题解:P1492 猩猩散步

· · 题解

P1492 猩猩散步

题目传送门\ \ 这题十分简单,不知道怎么评蓝的

解法

这题就是求 C^m_{n+m}。当你信心满满地想高精度暴力水过时,却发现出题人善良地卡掉了这个近似 O(n^2) 的做法,紧接着你看见了保留 100 位,不过很快发现保留位数后不能进行除法。这时我们就需要规避除法,转变成纯乘法。\ \ 我们知道结果一定是整数,就知道答案一定可以分解质因数。众所周知,C^m_{n+m}=(n+m)!\div n!\div m! 我们就可以提前预处理 (n+m)!,n!m! 的质因数分解式并用 (n+m)! 的分解式每一项的值减去 n!m! 的分解式每一项的值。这样我们就可以把这些质因数全堆在最后乘了。\ \ 质因数分解具体该怎么做呢?我们可以先筛出所有质数,再一次计算每个质数的个数。注意 4 给质因数 2 的贡献是 2,所以我们把每个质因数小于 n+m 的幂次方算出来,个数加给这个质因数。\ \ 然后就是连乘,还是像累乘一样,先定义一个变量为 1,然后每一个质因数用 to_string 打乘字符串高精度乘给这个变量,注意随时取 100 位。最后十个一组输出即可。\ \ 下面奉上代码,不要复制 qwq。

AC Code

#include<bits/stdc++.h>
using namespace std;
const int maxlen=110;
const int maxn=1e5+6;
vector<int>zs;//质数
int z[maxn];//是否是质数数组,可用 bool 类型村
int m[maxn];//质数数量数组
struct BIG{
    int len,d[maxlen];
};
BIG bian(BIG x){//高精度取 100 位
    if(x.len<=100)return x;
    x.len=100;
    return x;
}
BIG init(string s){//高精度处理字符串
    BIG res;
    for(int i=0;i<maxlen;i++)res.d[i]=0;
    int len=s.length();
    for(int i=0;i<len;i++) res.d[i]=s[len-1-i]-'0';
    while(len>1&&res.d[len-1]==0)len--;
    res.len=len;
    return res;
}
void output(BIG a){//高精度输出
    int clock=0;
    for(int i=a.len-1;i>=0;i--){
        cout<<a.d[i];//分行输出,clock计数,到十则开启下一轮
        clock++;
        if(clock==10)cout<<'\n',clock=0;
    }
    cout<<'\n';
}
BIG add(BIG a,BIG b){//高精度乘法
    BIG c;
    for(int i=0;i<maxlen;i++)c.d[i]=0;
    c.len=a.len;
    for(int i=0;i<a.len;i++){
        for(int j=0;j<b.len;j++){
            c.d[i+j]+=a.d[i]*b.d[j];
        }
    }
    c.len=a.len+b.len-1;
    for(int i=0;i<c.len;i++){
        c.d[i+1]+=c.d[i]/10;
        c.d[i]=c.d[i]%10;
    }
    while(c.d[c.len]>0){
        c.d[c.len+1]+=c.d[c.len]/10;
        c.d[c.len]%=10;
        c.len++;
    }   
    return c;
}
int main(){
    int a,b;
    cin>>a>>b;
    if(a>b)swap(a,b);
    memset(z,0x1,sizeof(z));
    z[1]=0;
    zs.push_back(2);
    for(int i=2;i<=a+b;){//找质数
        for(int j=1;j<=(a+b)/i;j++)z[i*j]=0;
        for(int k=i;k<=a+b+1;k++){
            if(z[k]){
                zs.push_back(k);
                i=k;
                break;
            }
        }
    }
    for(int i=0;i<zs.size();i++){
        for(int j=zs[i];j<=(a+b);j*=zs[i])
        m[zs[i]]+=(a+b)/j-a/j-b/j;//计算质数个数
    }
    BIG x=init("1");
    for(int i=0;i<zs.size();i++){//连乘
        for(int j=1;j<=m[zs[i]];j++){
            BIG y=init(to_string(zs[i]));
            x=add(x,y);
            x=bian(x);
        }
    }
    x.len=100;
    output(x);//输出
    return 0;
}

完结撒花!