关于高精度之下快速幂qpow时间复杂度退化

P1045 [NOIP2003 普及组] 麦森数

caojiaming @ 2022-11-16 20:33:14

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
string high(string num,string add,int k)
{
    int g=0;
    if(num.length()<add.length())
    {
        string t=num;
        num=add;
        add=t;
    }
    string t(num.length()-add.length(),'0');
    add=t+add;
    int len1=num.length(),len2=add.length();
    for(int i=len1-1;i>=0;i--)
    {
        int t=(num[i]-'0')+(add[i]-'0')+g;
        num[i]=t%k+'0';
        g=t/10;
    }
    if(g!=0)
    {
        num.insert(0,string(1,(char)g+'0'));
    }
    return num;
}
const int L=1e7;
int na[L],nb[L],nc[L];//na存储被乘数,nb存储乘数,nc存储积
string highcheng(string a,string b)//高精度乘法a,b,均为非负整数
{
    string s;
    int La=a.size(),Lb=b.size();
    fill(na,na+L,0);fill(nb,nb+L,0);fill(nc,nc+L,0);//将na,nb,nc都置为0
    for(int i=La-1;i>=0;i--){na[La-i]=a[i]-'0';};//将字符串表示的大整形数转成i整形数组表示的大整形数
    for(int i=Lb-1;i>=0;i--){nb[Lb-i]=b[i]-'0';};
    for(int i=1;i<=La;i++)
    {
        for(int j=1;j<=Lb;j++)
        {
            nc[i+j-1]+=na[i]*nb[j];//a的第i位乘以b的第j位为积的第i+j-1位(先不考虑进位)
        }
    }
    for(int i=1;i<=La+Lb;i++)
    {
        nc[i+1]+=nc[i]/10,nc[i]%=10;//统一处理进位
    }
    if(nc[La+Lb])
    {
        s+=nc[La+Lb]+'0';//判断第i+j位上的数字是不是0
    }
    for(int i=La+Lb-1;i>=1;i--)
        s+=nc[i]+'0';//将整形数组转成字符串
    return s;
}
string qpow(int i)
{
    if(i==0)
    {
        return "1";
    }
    if(!(i%2))
    {
        string temp=qpow(i/2);
        return highcheng(temp,temp);
    }
    else
    {
        return highcheng(qpow(i-1),"2");
    }
}
int main()
{
    int v;cin>>v;
    if(v==0)
    {
        cout<<pow(2,v);
        return 0;
    }
    if(v<0)
    {
        cout<<"1/";
        v*=-1;
    }
    string a=qpow(v);
    cout<<a.length()<<"\n";
    if(a.length()>500)
    {
        int cur=0;
        for(int i=a.length()-500;i<a.length();i++)
        {
            cout<<a[i];
            cur++;
            if((cur)%50)
            {
                continue;
            }
            cout<<endl;
        }
    }
    else
    {
        while(a.length()<500)
        {
            a="0"+a;
        }
        for(int i=0;i<a.length();i++)
        {
            cout<<a[i];
            if((i+1)%50)
            {
                continue;
            }
            cout<<endl;
        }
    }
    return 0;
}

全TLE 样例过了 出奇了


by FReQuenter @ 2022-11-16 20:43:38

您的乘法是 O(n^2) 的。到后面长度可能有几十万。只能留 500 位。


by FReQuenter @ 2022-11-16 20:44:40

乘法之前取模一下。


by caojiaming @ 2022-11-16 21:40:04

改了还是TLE


by caojiaming @ 2022-11-16 21:45:56

现在五点WA


by Crab_Tang @ 2023-08-20 13:18:36

@FReQuenter 大佬大佬,高精怎么取模啊


by FReQuenter @ 2023-08-20 16:36:50

@Robots75 除的过程中记录一下余数


|