zoukankan      html  css  js  c++  java
  • 湖南省第八届大学生程序设计大赛原题 D

    D - 平方根大搜索(UVA 12505 )
    Time Limit:5000MS     Memory Limit:131072KB     64bit IO Format:%lld & %llu

    Description

    在二进制中,2的算术平方根,即sqrt(2),是一个无限小数1.0110101000001001111...
    给定一个整数n和一个01串S,你的任务是在sqrt(n)的小数部分(即小数点之后的部分)中找到S第一次出现的位置。如果sqrt(n)是整数,小数部分看作是无限多个0组成的序列。

    Input

    输入第一行为数据组数T (T<=20)。以下每行为一组数据,仅包含一个整数n (2<=n<=1,000,000)和一个长度不超过20的非空01串S。

    Output

    对于每组数据,输出S的第一次出现中,第一个字符的位置。小数点后的第一个数字的位置为0。输入保证答案不超过100。

    Sample Input

    2
    2 101
    1202 110011 

    Sample Output

    2
    58 

    题意:将一个数开平方,得到小数部分和给定的字符串比较,输出相应的第一个位置
    分析:double存不下100位的精度,只有用模拟。题目太难,看解题报告理解了好久,下面是标程,加上了自己理解的注释,可能写的比较乱,表达不是很好,还望见谅

    #include<cstdio>
    #include<cstring>
    const int maxn=1111;
    char s[maxn];
    int a[maxn],b[maxn],res[maxn];
    int main(){
        int t,n;
        scanf("%d",&t);
        while(t--){
            scanf("%d%s",&n,s);
            memset(a,0,sizeof a);
            //将n分解成二进制,保存到a[280]->a[299];
            for(int i=19;i>=0;i--){
                if(n>=(1<<i)){
                    n-=(1<<i);
                    a[i+280]=1;
                }
            }
            memcpy(res,a,sizeof(a));//为什么要复制?多此一举的开了一个a数组
            for(int i=149;i>=0;i--){
                int b1=0;//标记
                /*为什么这里是149,而后面是139?因为前十位存的是整数部分!n化成二进制最多要20位,开埂号后最后为10位*/
                for(int j=299;j>149+i+1;j--)//目前查找到的开方数有149-i位,299-(149-i)=150+i;
                    if(res[j]==1){
                        /*前面如果某一位为1;当前b[i]必定上1,因为在后面加上一个1,平方后仍然小于原来的数;*/
                        b1=1;break;
                    }
    
                if(b1==0)//如果为0,比较res和b;确保商1的话,得到的平方小于n’;
                    for(int j=149;j>i;j--){
                        if(res[j+i+1]>b[j]){
                            b1=1;//一位一位比较,先找到比他大的,说明可以商1,先找到的比它小,那么只能商0
                            break;
                        }
                        if(res[j+i+1]<b[j]){
                            b1=-1;break;
                        }
                    }
                //我们这里来看看,00*00=0000,01*01=0001,10*10=0100,11*11=1001;
                //11*11=1001,111*111= 110001,110*110=100100,1111*1111= 11100001,1110*1110=11000100
                //商零,对前面的几位并没有任何影响,最后两位为0,不用修正,
                //商1,最后两位为01,对前面的数有一定的影响,需要修正
                if(b1==-1||b1==0&&res[i+i]==0&&res[i+i+1]==0) b[i]=0;
                /*与b[i]对应的连续的两位都为0的话,b[i]只能上0,上1的话res[i*i]必定为1;*/
                else{
                    b[i]=1;//商1,res减去对应位的b,
                    for(int j=149;j>i;j--)
                        res[j+i+1]-=b[j];//前面的减b[j],将n逐渐逼向0
                    res[i+i]--;//最后一位减1,倒数第二位为0,不需要修正
                    //修正res的值,将小于0的位补正
                    for(int j=i+1;j<300;j++)
                        if(res[j]<0){
                            /*如果某位小于零,则需要借位,将这一位加2(因为是二进制),下一位减一*/
                            res[j]+=2;
                            res[j+1]--;
                        }
                    //修正后的res一定大于0,否则不会商1.如果下次商0,得到的平方不会改变,不用修改res,
                    //如果商1,得到的平方必定小于n,将n剪掉b,不停的用二分,将n逼近于0
                }
            }
            n=strlen(s);
            //b中保存的是平方根(倒着保存的,即最后一位是小数点后第一位)
            for(int i=139;i>=0;i--){
                int b1=1;
                for(int j=0;j<n;j++)//对比,完全一样的就输出起始位置
                    if(b[i-j]!=s[j]-'0') b1=0;
                if(b1){
                    printf("%d
    ",139-i);
                    break;
                }
            }
        }
        return 0;
    }
    
  • 相关阅读:
    进程和线程
    进程通信、同步与调度
    文件和文件系统
    【nexys3】【verilog】小设计——拆弹游戏
    Qt4开发环境搭建(Qt4.8.7+mingw4.8.2+Qt Creator4.2.0)
    GPL和LGPL
    【rpi】使用putty远程连接rpi(ssh)
    mysql 命令 小结
    安装mysql zip 安装包 Navicat连接
    python虚拟环境 virtualenv工具
  • 原文地址:https://www.cnblogs.com/wabi87547568/p/4689924.html
Copyright © 2011-2022 走看看