高精度开平方

高精度开平方

时间限制: 1 Sec   内存限制: 128 MB

题目描述

输入

一个整数 N。 

输出

N 的平方根下取整。 

样例输入

 (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)

123456789012345678901234567890

样例输出

351364182882014

提示

对于 100%的数据,0<N<=10^1000。 


      别告诉我你想枚举,这种单调性问题肯定是二分答案啊,但是要用到高精度就很呵呵了,其实思想很简单,就是道堆代码的题罢了。不多说,先上代码吧

#include<cstdio>
#include<cstring>
#define max(a,b) a>b?a:b
struct node
{
    int s[10000];
    int len;
    node(){memset(s,0,sizeof(s));len=0;}//结构体默认构造函数
    void scan()//结构体成员函数,输入
    {
        char c[10000];
        scanf("%s",c);
        int o=strlen(c);
        for(len=0;len<o;len++) s[len]=c[o-len-1]-'0';
    }
    bool operator < (node p) const//重载运算符
    {
        if(len!=p.len) return len<p.len;
        for(int i=len-1;i>=0;i--) 
            if(s[i]!=p.s[i]) return s[i]<p.s[i];
        return 0;
    }
    bool operator == (node p) const
    {
        for(int i=max(len,p.len)-1;i>=0;i--)
            if(s[i]!=p.s[i]) return 0;
        return 1;
    }
    bool operator > (node p) const
    {
        if(len!=p.len) return len>p.len;
        for(int i=len-1;i>=0;i--) 
            if(s[i]!=p.s[i]) return s[i]>p.s[i];
        return 0;
    }
    node operator + (node a)
    {
        node c;
        c.len=max(len,a.len);
        for(int i=0;i<c.len;i++)
        {
            c.s[i]+=s[i]+a.s[i];
            if(c.s[i]>9) c.s[i]-=10,c.s[i+1]++;
        }
        if(c.s[c.len]) c.len++;
        return c;
    }
    node operator / (int a)
    {
        int x=0;
        node c;
        c.len=len;
        for(int i=len-1;i>=0;i--)
        {
            c.s[i]=(s[i]+x*10)/a;
            x=s[i]%a;
        }
        if(!c.s[len-1]) c.len--;
        return c;
    }
    node operator * (node a)
    {
        node c;
        for(int i=0;i<len;i++)
            for(int j=0;j<a.len;j++)
            {
                c.s[i+j]+=s[i]*a.s[j];
                if(c.s[i+j]>9) c.s[i+j+1]+=c.s[i+j]/10,c.s[i+j]%=10;
            }
        c.len=len+a.len;
        if(!c.s[c.len-1]) c.len--;
        return c;
    }
    node operator + (int a)
    {
        s[0]+=a;
        int i=0;
        while(s[i]>9) s[i]-=10,s[i+1]++,i++;
        if(s[len]) len++;
        return *this;
    }
    node operator - (int a)
    {
        s[0]-=a;
        int i=0;
        while(s[i]<0) s[i]+=10,s[i+1]--,i++;
        if(!s[len-1]) len--;
        return *this;
    }
};
int main()
{
    node n,l,r,m,f;
    n.scan();
    l.s[0]=0,l.len=1;
    r=n;
    while(l<r)//二分答案
    {
        m=(l+r+1)/2;
        f=m*m;
        if(f==n) {l=m;break;}
        else if(f>n) r=m-1;
        else l=m;
    }
    for(int i=l.len-1;i>=0;i--)
        printf("%d",l.s[i]);
}

      好,答案是对了,但是。。。光荣的TLE了,超时无奈啊。。。log一个一千位的数。。。显然,二分我们并不能修改,但是我们可以 修改高精度运算的方式----压位处理

      首先,我们数组的每个空间只存了一个一位数,浪费了这大好空间,循环也要超时,so,我们可以让数组的每个空间存一个多位数,这样做的话整个数组的长度就会大大减小,循环也会变快,但是压位处理要小心,不要遗留细节之处。先给一个存4位的代码吧。(只发修改了的地方)

struct node
{
    int s[10000];
    int len;
    node(){memset(s,0,sizeof(s));len=0;}
    void scan()//输入要修改
    {
        char c[10000];
        scanf("%s",c);
        int o=strlen(c);
        for(;(len+1)*4<=o;len++)
        {
            for(int i=4;i>=1;i--)
                s[len]=s[len]*10+c[o-len*4-i]-'0';
        }
        if(o%4!=0)
        {
            for(int i=0;i<o%4;i++)
                s[len]=s[len]*10+c[i]-'0';
            len++;
        }
        //for(int i=len-1;i>=0;i--) printf("%04d",s[i]);
        //printf("\n");
    }
    node operator + (node a)
    {
        node c;
        c.len=max(len,a.len);
        for(int i=0;i<c.len;i++)
        {
            c.s[i]+=s[i]+a.s[i];
            if(c.s[i]>9999) c.s[i]-=10000,c.s[i+1]++;//9和10要变成9999和10000
        }
        if(c.s[c.len]) c.len++;
        return c;
    }
    node operator / (int a)
    {
        int x=0;
        node c;
        c.len=len;
        for(int i=len-1;i>=0;i--)
        {
            c.s[i]=(s[i]+x*10000)/a;
            x=s[i]%a;
        }
        if(!c.s[len-1]) c.len--;
        return c;
    }
    node operator * (node a)
    {
        node c;
        for(int i=0;i<len;i++)
            for(int j=0;j<a.len;j++)
            {
                c.s[i+j]+=s[i]*a.s[j];
                if(c.s[i+j]>9999) c.s[i+j+1]+=c.s[i+j]/10000,c.s[i+j]%=10000;
            }
        c.len=len+a.len;
        if(!c.s[c.len-1]) c.len--;
        return c;
    }
    node operator + (int a)
    {
        s[0]+=a;
        int i=0;
        while(s[i]>9999) s[i]-=10000,s[i+1]++,i++;
        if(s[len]) len++;
        return *this;
    }
    node operator - (int a)
    {
        s[0]-=a;
        int i=0;
        while(s[i]<0) s[i]+=10000,s[i+1]--,i++;
        if(!s[len-1]) len--;
        return *this;
    }
};
int main()
{
    printf("%d",l.s[l.len-1]);
    for(int i=l.len-2;i>=0;i--)
        printf("%04d",l.s[i]);//%04d,例如2会输出0002,12会输出0012
}

显然,这样就快多了,但是。。。1042ms.........看来我们还需要继续压位。

当压位到5位及其以上时,用乘法的中间过程可能溢出,所以需要用long long。

struct node
{
    long long s[1005];
    int len;
    node(){memset(s,0,sizeof(s));len=0;}
    void scan()
    {
        char c[1010];
        scanf("%s",c);
        int o=strlen(c);
        for(;(len+1)*5<=o;len++)
        {
            for(int i=5;i>=1;i--)
                s[len]=s[len]*10+c[o-len*5-i]-'0';
        }
        if(o%5!=0)
        {
            for(int i=0;i<o%5;i++)
                s[len]=s[len]*10+c[i]-'0';
            len++;
        }
        //for(int i=len-1;i>=0;i--) printf("%04d",s[i]);
        //printf("\n");
    }
    node operator + (node a)
    {
        node c;
        c.len=max(len,a.len);
        for(int i=0;i<c.len;i++)
        {
            c.s[i]+=s[i]+a.s[i];
            if(c.s[i]>99999) c.s[i]-=100000,c.s[i+1]++;
        }
        if(c.s[c.len]) c.len++;
        return c;
    }
    node operator / (int a)
    {
        int x=0;
        node c;
        c.len=len;
        for(int i=len-1;i>=0;i--)
        {
            c.s[i]=(s[i]+x*100000)/a;
            x=s[i]%a;
        }
        if(!c.s[len-1]) c.len--;
        return c;
    }
    node operator * (node a)
    {
        node c;
        for(int i=0;i<len;i++)
            for(int j=0;j<a.len;j++)
            {
                c.s[i+j]+=s[i]*a.s[j];
                if(c.s[i+j]>99999) c.s[i+j+1]+=c.s[i+j]/100000,c.s[i+j]%=100000;
            }
        c.len=len+a.len;
        if(!c.s[c.len-1]) c.len--;
        return c;
    }
    node operator + (int a)
    {
        s[0]+=a;
        int i=0;
        while(s[i]>99999) s[i]-=100000,s[i+1]++,i++;
        if(s[len]) len++;
        return *this;
    }
    node operator - (int a)
    {
        s[0]-=a;
        int i=0;
        while(s[i]<0) s[i]+=100000,s[i+1]--,i++;
        if(!s[len-1]) len--;
        return *this;
    }
};
int main()
{
    printf("%lld",l.s[l.len-1]);
    for(int i=l.len-2;i>=0;i--)
        printf("%05lld",l.s[i]);
}
这就是压了5位,哦,终于AC了。爽。当然,用了long long应该能压更多位,大家自己去试吧。



  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值