D - 平方根大搜索
Time Limit:5000MS Memory Limit:131072KB 64bit IO Format:%lld & %llu
Submit Status Practice CSU 1114
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\n",139-i); break; } } } return 0; }
时间: 2024-11-08 12:32:38