湖南省第八届大学生计算机程序设计竞赛D题 平方根大搜索(题目链接)。
题目D 平方根大搜索
在二进制中,2的算术平方根,即sqrt(2),是一个无限小数1.0110101000001001111...
给定一个整数n和一个01串S,你的任务是在sqrt(n)的小数部分(即小数点之后的部分)中找出到S第一次出现的位置,如果sqrt(n)是整数,小鼠部分看作是无限个0组成的序列。
输入格式
输入第一行为数据组数T(T≤20)。以下每行为一组数据,仅包含一个整数n(2≤n≤1,000,000)和一个长度不超过20的非空01串S。
输出格式
对于每组数据,输出S的第一次出现中,第一个字符的位置。小数点后的第一个数字的位置为0。输入保证答案不超过100。
样例输入
2
2 101
1202 110011样例输出
2
58
解题思路:二分法(对于二进制,其实就是0、1枚举法)。用bitset来储存二进制小数,用二分法算出 的解。然后字符串匹配即可。
C++语言代码如下:
#include <cstdio>
#include <cstdlib>
#include <string>
#include <cmath>
#include <bitset>
using namespace std;
#define MAX_LENGTH 2250
#define DECIMAL_DIGITS 1000
#define FAC_MAX_LENGTH 150
#define FAC_DECIMAL_DIGITS 100
typedef bitset <MAX_LENGTH> BigInt;
typedef bitset <FAC_MAX_LENGTH> FacBigInt;
BigInt operator+ ( const BigInt & a, const BigInt & b )
{
BigInt result;
result.reset( );
int temp;
int carry = 0;
for ( int i = MAX_LENGTH - 1; i >= 0 ; i -- )
{
temp = a[i] + b[i] + carry;
carry = (temp >> 1);
result[i] = (temp & 1);
}
return result;
}
BigInt & operator+= ( BigInt & a, const BigInt & b )
{
int temp;
int carry = 0;
for ( int i = 0; i < MAX_LENGTH ; i ++ )
{
temp = a[i] + b[i] + carry;
carry = (temp >> 1);
a[i] = (temp & 1);
}
return a;
}
bool operator> ( const BigInt & a, const BigInt & b )
{
for ( int i = MAX_LENGTH - 1 ; i >= 0 ; i -- )
{
if ( a[i] > b[i] )
return true;
else if ( a[i] < b[i] )
return false;
}
return false;
}
inline BigInt FacBigIntToBigInt( const FacBigInt & n )
{
return BigInt(n.to_string()) << ( DECIMAL_DIGITS - FAC_DECIMAL_DIGITS );
}
BigInt & GetSq( const FacBigInt & n )
{
static BigInt result;
result.reset( );
BigInt m = FacBigIntToBigInt(n);
for ( int i = DECIMAL_DIGITS - FAC_DECIMAL_DIGITS ; i < FAC_MAX_LENGTH + DECIMAL_DIGITS - FAC_DECIMAL_DIGITS ; i ++ )
{
if ( m[i] )
result += ( m << i );
}
result >>= DECIMAL_DIGITS;
return result;
}
FacBigInt & GetSqrt( const unsigned long input )
{
static FacBigInt mid;
BigInt radicand = BigInt (input);
BigInt square;
radicand <<= DECIMAL_DIGITS;
unsigned long intPart = static_cast<unsigned long>(sqrt(input));
mid = intPart;
mid <<= FAC_DECIMAL_DIGITS;
if ( ( square = GetSq(mid) ) == radicand )
return mid;
for ( int i = FAC_DECIMAL_DIGITS - 1 ; i >= 0 ; i -- )
{
mid[i] = 1;
if ( ( square = GetSq(mid) ) == radicand )
break;
else if ( square > radicand )
mid[i] = 0;
}
return mid;
}
int main ( )
{
int test_cases;
unsigned long input;
char find_string[105];
FacBigInt root;
scanf( "%d", &test_cases );
while ( test_cases -- )
{
scanf( "%lu", &input );
root = GetSqrt( input );
scanf( "%s", find_string );
int pos = root.to_string().find(string(find_string),
FAC_MAX_LENGTH - FAC_DECIMAL_DIGITS ) - (FAC_MAX_LENGTH - FAC_DECIMAL_DIGITS);
printf( "%d\n", pos );
}
return EXIT_SUCCESS;
}