第八届湖南省赛D题 平方根大搜索

本文探讨如何在二进制数的平方根小数部分中查找特定的01序列,通过数学方法和算法实现精准定位。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

D - 平方根大搜索
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 

题解: 求出二进制小数点后120左右,在查找s串在ans串的位置就可以了。二进制小数位转换成十进制的方法是0或者1乘上2的(-n)次方,反过来是*2取整。然后不断逼近n就可以求出小数位120位了。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <cmath>
using namespace std;
int a1[10010],a2[10010],b[10000],c[10000],l1,l2,s[110000];
int l3,l4,l5,point,point2,point3,point1;
char ans[1000];
char ss[23];
int chengfa()
{
	int pos,i,j;
	memset(s,0,sizeof(s));
	for (i=1;i<=l4;i++)
		for (j=1,pos=i;j<=l4;j++)
			s[pos++]+=a2[i]*a2[j];
	pos-=1;
	for (i=1;i<=pos;i++)
	if (s[i]>=10)
	{
		if (i==pos) pos++;
		s[i+1]+=s[i]/10;
		s[i]%=10;
	}
	return pos;
}
void jia()
{
	int p=1,i;
	if (point > point1)
	{
		for (i=1;i<=point - point1;i++)
			a2[p++]=a1[i];
		int tt=1;
		for (i=point - point1+1;i<=l1;i++)
			a2[p++]=a1[i]+c[tt++];
		point2=point;
	}
	else
	{
		for (i=1;i<=point1-point;i++)
			a2[p++]=c[i];
		int tt=i;
		for (i=1;i<=l1;i++)
			a2[p++]=a1[i]+c[tt++];
		point2=point1;
	}
	int kk=0;
	p--;
	for (i=1;i<=p;i++)
	{
		a2[i]+=kk;
		kk=a2[i]/10;
		a2[i]%=10;
	}
	if (kk!=0) a2[++p]=kk;
	l4=p;
}
int gobj()
{
	int sl=l5,bl=l2;
	if (sl-point3>bl) return 1;
	else if (sl-point3<bl) return -1;
	while (sl>0 && bl>0)
	{
		if (s[sl]>b[bl]) return 1;
		if (s[sl]<b[bl]) return -1;
		sl--;bl--;
	}
	if (sl==0) return 0;
	else return 1;
}
int main()
{
	int T,n;
	scanf("%d",&T);
	while (T--)
	{
		memset(ans,0,sizeof(ans));
		memset(a1,0,sizeof(a1));
		memset(a2,0,sizeof(a2));
		memset(c,0,sizeof(c));
		memset(b,0,sizeof(b));
		scanf("%d",&n);
		getchar();
		scanf("%s",&ss);
		int m=sqrt(n);
		int mm=m;
		int j=1;
		l1=0;
		point=0;
		while (mm)
		{
			a1[j++]=mm % 10;
			mm/=10;
			l1++;
		}
		point=0;
		mm=n;
		j=1;l2=0;
		while (mm)
		{
			b[j++]=mm%10;
			mm/=10;
			l2++;
		}
		c[1]=1;l3=1;
		int i;
		for (i=1;i<=130;i++)
		{
			for (j=1;j<=l3;j++)
				c[j]*=5;
			int kk=0;
			for (j=1;j<=l3;j++)
			{
				c[j]+=kk;
				kk=c[j]/10;
				c[j]=c[j]%10;
			}
			if (kk) c[++l3]=kk;
			point1=i;
			jia();
			/*for (j=l4;j>0;j--)
			{
				if (point2==j) cout<<".";
				printf("%d",a2[j]);
			}
			cout<<endl;*/
			l5=chengfa(); //平方后长度
			point3=2*point2; //平方后小数点位置
			/*for (j=l5;j>0;j--)
			{
				if (point3==j) cout<<".";
				printf("%d",s[j]);
			}
			cout<<endl;*/
			int re=gobj();
			if (re==1) //1:s>b -1:s<b
				ans[i-1]='0';
			else if (re==-1)
			{
				ans[i-1]='1';
				memset(a1,0,sizeof(a1));
				for (j=1;j<=l4;j++)
					a1[j]=a2[j];
				l1=l4;
				point=point2;
			}
			else break;
		}
		for (j=i;j<=130;j++)
			ans[i]='0';
		ans[130]='\0';
		//cout<<ans<<endl;
		cout<<strstr(ans,ss) - ans << endl;
	}
	return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值