NOIPの模拟_2016_7_19_t1_腐败

本文介绍了一个关于质因数分解与快速乘法的算法问题,通过将输入序列分解为质因数并利用快速乘法计算结果,解决了大数运算过程中可能遇到的溢出问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

这里写图片描述
input
第一行一个正整数n,表示序列长度
第二行n个正整数,为给出的序列A

Sample Input
3
6 4 12

Output
一个非负整数,为答案。

Sample Output
13824

Data Constraint
50%:n<=3000;
100%:n<=30000,A[i]<=10^7

题目の大意

这题并不需要2333(+10086);

我比赛时の想法与吐槽

看到题先发动技能:奥义*蒙逼!蒙逼几分钟之后愉悦的想到了分解质因数,然后就愉悦的开始打了,打到一半发现这个模数十分神奇,似乎会爆int64!?于是有好的与同学交流了一番,回忆起了以前忘记的快速乘(其实我怎么看也都不快啊)。但是因为我比较垃圾,打的代码也十分捞,十分难调,两个小错误调到了下午四点555。

大概思路

当前我们正在处理一个数x,那么我们先把ta分解成zs=1pkss的形式,然后把每一个小于sqrt(107)的数(也就是小于3162)放到一个f[i,j]中,f[i,j]表示在现在已经处理过的数中因子i的个数为j的个数,若有一个质数大于3162,容易发现这个质数在每一个数中指数最大为1,所以我们用一个g[i]来分开存储,这样就解决了空间的问题,然后我们分情况讨论:
设x的质因子p有tt个,分两个部分计算答案
1:f[p,1—>tt],对于这一部分我们给答案*f[p,q]*l(l为pq
2: f[p,tt+1—>cc[p]],对于这一部分答案*f[p,q]*l(l为ptt,设cc[p]=z,则cc[p]表示不大于107的最大的pz)
对于p<3162和p>3162当然是要分开处理的啦

快速乘

设cy=107,我们现在要求a*b的积。
设a1=a mod cy;
a2=a div cy;
b1=b mod cy;
b2=b div cy;
那么a*b=(a2*cy+a1)*(b2*cy+b1),然后把ta拆开,把四项的答案都算出来然后相加就可以了,在计算的过程每做一步就mod一次就不会runtime error 了
贴代码(好长啊,还有好多调试时候的注释懒得删了2333~~)

CONST md=100000000009;cy=10000000;
VAR
    T:ARRAY[0..10005,0..100]OF LONGINT;
    A:ARRAY[0..30005]OF LONGINT;
    B:ARRAY[0..10000005]OF LONGINT;
    Q,CC:ARRAY[0..10005]OF LONGINT;
    PP:ARRAY[0..1005,0..20005]OF int64;
    I,J,K,L,N,x,tt,ss:LONGINT;
    ANS,aa:INT64;
procedure make_Prime_Number;
var
    i,j:longint;
    k:int64;
    bz:array[0..10005]of boolean;
begin
    fillchar(bz,sizeof(bz),false);
    for i:=2 to 3500 do
    if bz[i]=false then
    begin
        j:=i+i;
        while j<3500 do
        begin
            bz[j]:=true;
            inc(j,i);
        end;
    end;
    for i:=2 to 3162 do
    if bz[i]=false then
    begin
        inc(q[0]);
        q[q[0]]:=i;
        k:=i;
        j:=0;
        while k<30000*3162 do
        begin
            inc(j);
            k:=k*i;
        end;
        cc[i]:=j;
    end;
end;
PROCEDURE MAKE_PP;
BEGIN
    FOR I:=2 TO 1000 DO
    BEGIN
        PP[I,1]:=I;
        FOR J:=2 TO 20000 DO PP[I,J]:=(PP[I,J-1]*I) MOD MD;
    END;
END;
function fate(x,y:int64):int64;
var
    a1,a2,b1,b2,ls:int64;
begin
    a1:=x mod cy;
    a2:=x div cy;
    b1:=y mod cy;
    b2:=y div cy;
    ls:=(((((a2*b2) mod md)*cy) mod md)*cy) mod md;
    ls:=ls+(((a2*b1) mod md)*cy) mod md;
    ls:=ls+(((a1*b2) mod md)*cy) mod md;
    ls:=(ls+a1*b1) mod md;
    exit(ls);
   // exit((x*y) mod md);
end;
BEGIN
    //assign(input,'1.in'); reset(input);
    READLN(N);
    FOR I:=1 TO N DO READ(A[I]);
    READLN;
    ANS:=A[1];
    FOR I:=2 TO N DO ANS:=fate(ANS,A[I]);
    MAKE_Prime_Number;
    MAKE_PP;
    aa:=(cy*cy) mod md;
    for i:=1 to n do
    begin
        x:=a[i];
        j:=1;
        while (q[j]<x) and (j<q[0]) do
        begin
            tt:=0;
            while x mod q[j]=0 do
            begin
                inc(tt);
                x:=x div q[j];
            end;
            if tt>0 then
            begin
                l:=1;
                for k:=1 to tt do
                begin
                    l:=(l*q[j]) mod md;
                    if t[q[j],k]>0 then
                    begin
                        if l<=1000 then ans:=fate(ans,pp[l,t[q[j],k]]) else
                        for ss:=1 to t[q[j],k] do ans:=fate(ans,l);
                    end;
                end;
                for k:=tt+1 to cc[q[j]] do
                if t[q[j],k]>0 then
                begin
                    if l<=1000 then ans:=fate(ans,pp[l,t[q[j],k]]) else
                    for ss:=1 to t[q[j],k] do ans:=fate(ans,l);
                end;
                inc(t[q[j],tt]);
            end;
            inc(j);
            if sqrt(x)<q[j] then
            begin
                if x<3162 then
                begin
                    if x=1 then continue;
                    l:=x;
                    if t[x,1]>0 then
                    if l<=1000 then ans:=fate(ans,pp[l,t[x,1]]) else
                    for ss:=1 to t[x,1] do ans:=fate(ans,l);
                    inc(t[x,1]);
                    for k:=2 to cc[x] do
                    if t[x,k]>0 then
                    begin
                        if l<=1000 then ans:=fate(ans,pp[l,t[x,k]]) else
                        for ss:=1 to t[x,k] do ans:=fate(ans,l);
                    end;
                end;
                break;
            end;
        end;
        if x>3162 then
        begin
            for ss:=1 to b[x] do
            ans:=fate(ans,x);
            inc(b[x]);
        end;
    end;
    writeln(ans);
   // close(input);
END.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值