SGU 111 Very simple problem

叫Very simple problem的通常都不简单。。。

此题就是让你求一个数的平方根取整。但是这个数特别大10^1000。所以不能(int)sqrt。。

查了一下解题报告,有两种方法。

第一种是模拟徒手开方,第二种是高精度+二分。

这里先整理徒手开方的解法。

(1)把被开方数(如22146436)从右向左每隔两位用撇号分开(如22’14’64’36); 
(2)从左边第一段(如22)求得算术平方根的第一位数字(如4) ; 
(3)从第一段减去这第一位数字的平方(如22-42=6),再把被开方数的第二段写下来,作为第一个余数(如614); 
(4)把所得的第一位数字(如4)乘以20,去除第一个余数所得的商的整数部分(如614÷(4×20)=7.675的整数部分7)作为试商(注:如果这个整数部分大于或者等于10,就改用9作试商,如果第一个余数小于第一位数字乘以20的积,则得试商0); 
(5)把第一位数字的20倍加上试商的和,乘以这个试商所得值不大于第一个余数时(如(4×20+7)×7=609≤614),这个试商就是算术平方根的第二位数字(注:如果所得的积大于余数时,就要把试商减去1再试,直到积小于或者等于余数为止); 
(6)用第一个余数减去第一位数字的20倍加上试商的和乘以该试商所得值的差(如614-609=5),往后用同样的方法,继续求算术平方根的其他各位数字。



把这种过程编程实现即可。

如果位数是奇数,则在最高位前加一个0,使其依然可以被两两分割。

省去试商的过程,从9开始枚举到0,找到t,使得目前的 (ans*20+t)*t 不大于当前余数。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
bool Check(char *rem,int s,int e,char *ans,int la,char *s3)
{
    int ls3,ite,i,n;
    char s1[2000],s2[2000];
    strcpy(s1,rem);
    strcpy(s2,ans);
    s3[0]=ans[la-1];
    n=s3[0]-'0';
    ite=0;
    ls3=1;
    //乘以20
    for (i=la-2; i>=0; i--)
    {
        ite+=(s2[i]-'0')*2;
        s3[ls3]=ite%10+'0';
        ite/=10;
        ls3++;
    }
    if (ite != 0)
    {
        s3[ls3]=ite+'0';
        ls3++;
    }
    while (s3[ls3-1] == '0' && ls3 > 1)
        ls3--;
    s3[ls3]='\0';
    ite=0;
    //加上n后,再乘以n
    for (i=0; i<ls3; i++)
    {
        ite+=(s3[i]-'0')*n;
        s3[i]=ite%10+'0';
        ite/=10;
    }
    while (ite != 0)
    {
        s3[ls3]=ite%10+'0';
        ite/=10;
        ls3++;
    }
    while (s3[ls3-1] == '0' && ls3 > 1)
        ls3--;
    s3[ls3]='\0';
    strrev(s3);
    if (ls3 == 1)
    {
        s3[ls3]=s3[0];
        s3[0]='0';
        ls3++;
    }
    //判断大小
    if (e-s < ls3)
    {
        return false;
    }
    else if (e-s > ls3)
    {
        return true;
    }
    else                   //位数相等的情况下
    {
        for (i=0; i<ls3; i++)
        {
            if (rem[s+i] < s3[i])
                return false;
            else if (rem[s+i] > s3[i])
                return true;
        }
        return true;
    }
}
void ChangeRem(char *rem,int *s,int e,char *s3)
{
    int ls,i;
    i=e-1;
    ls=strlen(s3)-1;
    while (ls >= 0)
    {
        if (rem[i] >= s3[ls])
        {

            rem[i]-=s3[ls];
            rem[i]+='0';
        }
        else
        {
            rem[i-1]-=1;
            rem[i]=(rem[i]-s3[ls])+10+'0';
        }
        ls--;
        i--;
    }
    while (rem[(*s)] == '0')
    {
        (*s)++;
    }
}
char *BigSqrt(char *str)
{
    int i,j,ls,la,lr,sr;
    char num[2000],ans[2000],rem[2000],tc,tstr[2000];
    la=0;
    lr=0;
    sr=0;
    ls=strlen(str);
    if ((ls&1) == 1)                //如果位数是奇数,则在最高位加0
    {
        num[0]='0';
        strcpy(num+1,str);
        ls++;
    }
    else
    {
        strcpy(num,str);
    }
    for (i=0; i<ls; i+=2)
    {
        rem[lr]=num[i];
        rem[lr+1]=num[i+1];
        lr+=2;
        tc='9'+1;
        while (tc--)             //从9到0
        {
            ans[la]=tc;
            ans[la+1]='\0';
            if (Check(rem,sr,lr,ans,la+1,tstr) == true)          //判断(ans*20+t)*t是否不大于当前余数
            {
                //满足,对当前余数remaider-(ans*20+t)*t
                la++;
                ChangeRem(rem,&sr,lr,tstr);
                break;                                     //找到了平方根的这一位上的数,直接跳出
            }
        }
    }
    return ans;
}
int main()
{
    char str[2000];
    scanf("%s",str);
    printf("%s",BigSqrt(str));
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值