UVA_701
看了别人的解题报告之后,发现可以枚举剩余数字的位数,我们不妨设其为k,那么我们会得到不等式,N*10^k<=2^E<N*10^k,化简之后就可以得到log2(N)+k*log2(10)<=E<log2(N+1)+k*log2(10),我们设左右边界为a、b的话,问题就等价于如果在枚举k的过程中出现了[a,b)内有一个整数点的话,那个值就是E。
首先来讲,由于b-a=log2((N+1)/N)<log2(2)=1,所以区间内如果出现整数点的话最多只有一个。接着,我们要解决的问题就是,随着我们不断地枚举k,是否一定在某一刻内出现[a,b)内有一个整数点的情况呢?
对于这个问题我是这样想的,实际我们就是希望b-a这么宽的区间能够覆盖某个整数点,而对于k*log2(10)来讲,由于log2(10)是一个无理数,因此k*log2(10)-[k*log2(10)]不会有一个固定的整数周期,甚至不会出现两个不同的k使得它们的的值相等,这点可以用反证法证明。再加之k是整数,感觉上这个表达式的值应该在[0,1)之内分布的比较均匀,这样我们多次枚举之后,应该会出现某一时刻使得b-a这么宽的区间覆盖一个整数点。
当然,前面只是感觉,也只是说理论上可以找到,但我们不妨分析一下b-a的取值,在最坏的情况下,区间长度只有7*10^(-10)左右,即便前面所说的表达式的值分布得再均匀,1s也不过能细化到10^(-8),也就是说大概能保证区间[a,b)长度是10^(-8)左右的数据能在1s之内找到解,这远远不能满足最坏的情况。不信的话可以把这种枚举的程序出一些9位数的数据试一下,就会发现程序跑得很慢,因为通常找到的解是8位数以上的。
总而言之,我现在还没找到很“有效”的算法,之所以枚举能过,应该也是数据出得比较小的缘故。
后来听YTQ说,由于这个题目是2000年出的,所以可能题目中所指的整数E是在65536之内的,这样的话枚举范围就很小了。
#include<stdio.h>
#include<string.h>
#include<math.h>
long long int N;
char b[20];
void solve()
{
int k, x, y;
sprintf(b, "%d", N);
for(k = strlen(b) + 1;; k ++)
{
x = (long long int)(log2(N) + k * log2(10));
y = (long long int)(log2(N + 1) + k * log2(10));
if(x != y)
{
printf("%d\n", y);
break;
}
}
}
int main()
{
while(scanf("%lld", &N) == 1)
{
solve();
}
return 0;
}