POJ2109 高精度(含大数开方)+二分

来源:互联网 发布:python统计字符串个数 编辑:程序博客网 时间:2024/05/17 06:09


1 高精度(含大数开方)+二分

一个技巧和三点注意:

技巧:假设k^n=p;(k的n次方),那么p的位数/n得到的是k的位数!例如:n=7,p=4357186184021382204544,p的位数为22,用22/7的结果向上取整,得到4,即为k的位数,也就是说k的取值范围是1000~9999。(引自code_pang不利用这一点,高精度+直接二分,也会超时。用这一个技巧合理缩小二分的范围。

注意:看code的main中的注释。

(二分思想不熟练,因为二分算法很高效,所以一定要暴力点直接确定left和right,然后根据情况,优化也是将left变大和right变小,而不会是其他奇怪的情况。另外,注意left=mid+1,right=mid-1,这很重要)

#include <stdio.h>#include <math.h>#include <string.h>#include <iostream>#include <string>#include <algorithm>using namespace std;const int numlen = 105; // 位数int max(int a, int b) { return a>b?a:b; }struct bign {    int len, s[numlen];    bign() {        memset(s, 0, sizeof(s));        len = 1;    }    bign(int num) { *this = num; }    bign(const char *num) { *this = num; }    bign operator = (const int num) {        char s[numlen];        sprintf(s, "%d", num);        *this = s;        return *this;    }    bign operator = (const char *num) {        len = strlen(num);        while(len > 1 && num[0] == '0') num++, len--;        for(int i = 0;i < len; i++) s[i] = num[len-i-1] - '0';        return *this;    }    void deal() {        while(len > 1 && !s[len-1]) len--;    }    bign operator + (const bign &a) const {        bign ret;        ret.len = 0;        int top = max(len, a.len) , add = 0;        for(int i = 0;add || i < top; i++) {            int now = add;            if(i < len) now += s[i];            if(i < a.len)   now += a.s[i];            ret.s[ret.len++] = now%10;            add = now/10;        }        return ret;    }    bign operator - (const bign &a) const {        bign ret;        ret.len = 0;        int cal = 0;        for(int i = 0;i < len; i++) {            int now = s[i] - cal;            if(i < a.len)   now -= a.s[i];            if(now >= 0)    cal = 0;            else {                cal = 1; now += 10;            }            ret.s[ret.len++] = now;        }        ret.deal();        return ret;    }    bign operator * (const bign &a) const {        bign ret;        ret.len = len + a.len;        for(int i = 0;i < len; i++) {            for(int j = 0;j < a.len; j++)                ret.s[i+j] += s[i]*a.s[j];        }        for(int i = 0;i < ret.len; i++) {            ret.s[i+1] += ret.s[i]/10;            ret.s[i] %= 10;        }        ret.deal();        return ret;    }    //乘以小数,直接乘快点    bign operator * (const int num) {        bign ret;        ret.len = 0;        int bb = 0;        for(int i = 0;i < len; i++) {            int now = bb + s[i]*num;            ret.s[ret.len++] = now%10;            bb = now/10;        }        while(bb) {            ret.s[ret.len++] = bb % 10;            bb /= 10;        }        ret.deal();        return ret;    }    bign operator / (const bign &a) const {        bign ret, cur = 0;        ret.len = len;        for(int i = len-1;i >= 0; i--) {            cur = cur*10;            cur.s[0] = s[i];            while(cur >= a) {                cur -= a;                ret.s[i]++;            }        }        ret.deal();        return ret;    }    bign operator % (const bign &a) const {        bign b = *this / a;        return *this - b*a;    }    bign operator += (const bign &a) { *this = *this + a; return *this; }    bign operator -= (const bign &a) { *this = *this - a; return *this; }    bign operator *= (const bign &a) { *this = *this * a; return *this; }    bign operator /= (const bign &a) { *this = *this / a; return *this; }    bign operator %= (const bign &a) { *this = *this % a; return *this; }    bool operator < (const bign &a) const {        if(len != a.len)    return len < a.len;        for(int i = len-1;i >= 0; i--) if(s[i] != a.s[i])            return s[i] < a.s[i];        return false;    }    bool operator > (const bign &a) const  { return a < *this; }    bool operator <= (const bign &a) const { return !(*this > a); }    bool operator >= (const bign &a) const { return !(*this < a); }    bool operator == (const bign &a) const { return !(*this > a || *this < a); }    bool operator != (const bign &a) const { return *this > a || *this < a; }    string str() const {        string ret = "";        for(int i = 0;i < len; i++) ret = char(s[i] + '0') + ret;        return ret;    }};istream& operator >> (istream &in, bign &x) {    string s;    in >> s;    x = s.c_str();    return in;}ostream& operator << (ostream &out, const bign &x) {    out << x.str();    return out;}// 大数开平方bign Sqrt(bign x) {    int a[numlen/2];    int top = 0;    for(int i = 0;i < x.len; i += 2) {        if(i == x.len-1) {            a[top++] = x.s[i];        }        else            a[top++] = x.s[i] + x.s[i+1]*10;    }    bign ret = (int)sqrt((double)a[top-1]);    int xx = (int)sqrt((double)a[top-1]);    bign pre = a[top-1] - xx*xx;    bign cc;    for(int i = top-2;i >= 0; i--) {        pre = pre*100 + a[i];        cc = ret*20;        for(int j = 9;j >= 0; j--) {            bign now = (cc + j)*j;            if(now <= pre) {                ret = ret*10 + j;                pre -= now;                break;            }        }    }    return ret;}int main(){    //test:    bign aa=6;    bign bb=7;    bign cc=(aa+bb)/2;    cout<<cc<<endl;    int a;    bign b;    int flag;    while(cin>>a>>b){        flag=1;        int len=b.len;        int pos;        if(len%a==0){                pos=len/a;        }        else if(len%a!=0){            pos=len/a+1;        }        bign sum=1;        bign mid;        bign left=pow(10.0,(int)pos-1);        bign right=pow(10.0,(int)pos);        /*在math.h中,函数pow有三种重载形式:        long double pow(long double,int)        float pow(float,int)        double pow(double,int)        对于所给的参数int,int,如果编译器无法判断应该匹配哪个函数,因此报编译错误        可以将代码改为pow(10.0,(int)i)       */        while(left<=right){            mid=(left+right)/2;            sum=1;            for(int i=1;i<=a;i++){                sum=mid*sum;            }            if(sum==b){                cout<<mid<<endl;                break;            }            else if(sum<b){                left=mid+1;//二分尤其不要忘记,left=mid+1 而非=mid!            }            else if(sum>b){                right=mid-1;//二分尤其不要忘记,right=mid-1 而非=mid!            }            if(left>right){                flag=0;                break;            }        }        //然而OJ给的数据并不是像题目中所说k一定是整数,所以最后取满足k^n=p的不大于k的最大的整数。        //另外,还要注意最后判断一步时,也要判断sum>b是否会出现这种情况,如果不判断提交WA,判断就AC了。但为什么还要加sum>b的判断?!不理解。        if(!flag){            mid=(left+right)/2;            sum=1;            for(int i=1;i<=a;i++){                sum=mid*sum;            }            if(sum>b){                cout<<mid-1<<endl;            }            else{                cout<<mid<<endl;            }        }    }}

2
直接用double,pow。
先分清数值范围和有效数字的区别,以下是double的描述:
C语言中,双精度浮点(double)型,占8 个字节(64位)内存空间。其数值范围为1.7E-308~1.7E+308,双精度完全保证的有效数字是15位,16位只是部分数值有保证,而单精度保证7位有效数字,部分数值有8位有效数.
所以对于此题中,p<=10^101 ,(10的101次方),可以用double装进去,但是如果cin>>p,cout<<p,就只显示16位,多了的就变成0了,但是对于本题的测试数据而言,以simple input中最后一个为例:
如果测试数据为:
7     4357186184021382204544
实际上所处理数据是:
7     4357186184021382000000
那4357186184021382000000开7次方的结果自然就是1234。
为什么不是1233或者1235呢?
12337=4332529576639313702577
12347=4357186184021382204544
12357=4381962969567270546875
可以看出在double型所能表示的精度范围内,它们三个值已经被区分开了。(引用自code_pang)

拓展:

C语言里对float类型数据的表示范围为-3.4*10^38+3.4*10^38double-1.7*10^-308~1.7*10^308long double-1.2*10^-4932~1.2*10^4932.

类型

比特(位)数

有效数字

数值范围

float

32

6~7

-3.4*10^38+3.4*10^38

double

64

15~16

-1.7*10^-308~1.7*10^308

long double

128/

18~19

-1.2*10^-4932~1.2*10^4932

(引用自Roberl)
#include <iostream>#include <math.h>using namespace std;int main(){    double a,b,c;    while(cin>>a>>b){        if(a==0){            break;        }        cout<<pow(b,1/a)<<endl;    }    return 0;}



0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 老婆跟人跑了怎么办啊 父母50了要离婚怎么办 父母吵架了我该怎么办 父母看孩子总是吵架怎么办 20岁父母离婚我怎么办 碰到没素质的人怎么办 父母抛弃了我该怎么办 父母说家里没钱困难怎么办 遇到素质低的老婆怎么办 孩子考试心里素质差怎么办 5岁儿童脾气不好怎么办 有一个素质差的父母怎么办 孩子对什么都无所谓怎么办 孩子在学习上无所谓怎么办 孩子对学习无所谓的态度怎么办 孩子不上进什么都无所谓怎么办 倔强的学生不理老师怎么办 一岁宝宝特别犟怎么办 孩子遇到问题喜欢发脾气怎么办 企业培养新人跑了怎么办 二年级学生读不懂题目怎么办 6岁宝宝有鼻炎怎么办 外地儿童怎么办北京医保卡 江苏联宝投资的钱怎么办 银行叫开了证券怎么办 中班心理健康我不开心了怎么办 大学生心理健康课总是抢不到怎么办 孩子成绩提不上去怎么办 孩子数学不开窍怎么办 二年级 初中孩子语文不开窍怎么办 分到的班级都是差生怎么办 初三了英语差怎么办呀 初三了英语差的很怎么办 五年级英语太差怎么办 听课效率没有自学效率高怎么办 小学生不好好写作业怎么办 带的家教成绩没有提高怎么办 学生出国学校成绩证明怎么办 学生成绩考差了班主任怎么办 高一的学生成绩跟不上怎么办 综合素质评价手册丢了怎么办