luogu1625 求和

蒟蒻也能写出来的AC代码!显然题目是让求

0!m!+1!(m+1)!+2!(m+2)!++(n1)!(m+n1)!

易通分为

0!(m+n1)!m!+1!(m+n1)!(m+1)!++(n1)!(m+n1)!(m+n1)!(m+n1)!

观察到分母是个奇大无比的数,倘若是硬算分母最后再除免不了高精除高精。哦我的老伙计,看在梅林的胡子的面子上,你一定不想写它的。于是我们就有一个优化:先将分母分解质因数,最后进行高精除低精约分

再考虑分子。可以发现,分子可以化成好多个 xyz ,且如果我们知道某一项,那么其下一项可以通过 x 乘某个数,z乘某个数(即 yz 除某个数,且除完必定是整数)得到,然后分子总和再加上它。这样就会跑得飞快。

细节也是需要注意的。这里注意一点,我的除法为了这道题做了点改动,即倘若有操作bool qaq=a/b;其中a为高精度数,b为int,要是 b|a 则有qaq被赋值true, 且a被b除掉。否则,qaq被赋值为false,且a不发生改变

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
using namespace std;
struct bigInt{
    int num[2500], len;
    bigInt operator+(bigInt &x)const{
        bigInt re;
        memset(re.num, 0, sizeof(re.num));//不加初始化大约会有奇怪的错误,我调了一个小时QAQ 
        re.len = max(len, x.len);
        for(int i=1; i<=re.len; i++)
            re.num[i] = num[i] + x.num[i];
        int jw=0;
        for(int i=1; i<=re.len; i++){
            re.num[i] += jw;
            jw = re.num[i] / 10;
            re.num[i] %= 10;
        }
        if(jw)
            re.num[++re.len] = jw;
        return re;
    }
    bigInt operator*(int &x)const{
        bigInt re;
        memset(re.num, 0, sizeof(re.num));
        re.len = len;
        for(int i=1; i<=re.len; i++)
            re.num[i] = num[i] * x;
        int jw=0;
        for(int i=1; i<=re.len; i++){
            re.num[i] += jw;
            jw = re.num[i] / 10;
            re.num[i] %= 10;
        }
        while(jw){
            re.num[++re.len] = jw%10;
            jw /= 10;
        }
        return re;
    }
    bool operator/(const int &x){
        bigInt re;
        memset(re.num, 0, sizeof(re.num));
        re.len = len;
        int tw=0;
        for(int i=len; i>=1; i--){
            tw = tw * 10 + num[i];
            re.num[i] = tw / x;
            tw %= x;
        }
        if(tw)  return false;//除不干净 
        while(!re.num[re.len])  re.len--;
        if(!re.len) re.len++;
        len = re.len;
        for(int i=1; i<=re.len; i++)
            num[i] = re.num[i];
        return true;
    }
    bigInt prt(){//输出函数 
        for(int i=len; i>=1; i--)
            putchar(num[i]+'0');
        putchar('\n');
    }
}fz, fztemp, fm;//fz表示分子,fm表示分母,fztemp表示当前处理分子的那一项 
vector<int> zys;//质因数 
int n, m;
bool isp[1005];
void shai(){//筛法筛质数 
    memset(isp, true, sizeof(isp));
    isp[0] = isp[1] = false;
    for(int i=2; i<=1000; i++)
        if(isp[i])
            for(int j=i+i; j<=1000; j+=i)
                isp[j] = false;
}
void makezys(int x){//对某个数分解质因数 
    for(int i=2; i<=x; i++)
        if(isp[i])
            while(x%i==0){
                zys.push_back(i);
                x /= i;
            }
}
int main(){
    cin>>n>>m;
    shai();
    fztemp.len = fm.len = 1;
    fztemp.num[1] = fm.num[1] = 1;
    fz.len = 1;
    fz.num[1] = 0;
    for(int i=1; i<=n+m-1; i++)
        makezys(i);
    for(int i=m+1; i<=n+m-1; i++)
        fztemp = fztemp * i;//先处理出0!*(n+m-1)!/m! 
    for(int i=0; i<=n-1; i++){
        if(i)   fztemp / (m+i);
        if(i)   fztemp = fztemp * i;//为了避免0!的尴尬加上if(i) 
        fz = fz + fztemp;
    }
    for(int i=0; i<zys.size(); i++){
        if(fz/zys[i])   ;
        else            fm = fm*zys[i];//不可约分,只好在分母中保留它了 
    }
    fz.prt();
    fm.prt();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值