POJ2109:Power of Cryptography

点击打开题目链接


Power of Cryptography

Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 16059   Accepted: 8103

Description

Current work in cryptography involves (among other things) large prime numbers and computing powers of numbers among these primes. Work in this area has resulted in the practical use of results from number theory and other branches of mathematics once considered to be only of theoretical interest. 
This problem involves the efficient computation of integer roots of numbers. 
Given an integer n>=1 and an integer p>= 1 you have to write a program that determines the n th positive root of p. In this problem, given such integers n and p, p will always be of the form k to the n th. power, for an integer k (this integer is what your program must find).

Input

The input consists of a sequence of integer pairs n and p with each integer on a line by itself. For all such pairs 1<=n<= 200, 1<=p<10 101 and there exists an integer k, 1<=k<=10 9 such that k n = p.

Output

For each integer pair n and p the value k should be printed, i.e., the number k such that k n =p.

Sample Input

2 16
3 27
7 4357186184021382204544

Sample Output

4
3
1234

Source

México and Central America 2004


=====================================题目大意=====================================


根据等式K^N=P和已经给出的整数N和整数P求解整数K的值。


=====================================算法分析=====================================


一、Double And Power:

    

   本来直呼本题数据天坑,居然用double保存数据后直接调用power函数就可以得出答案。后来才发现坑人的是自己不是题

  目数据。。。

  

   首先肯定:当数据在double可表示的精度范围内时答案是不可能出错的。

   然后又知:double可以准确表示出17位以下的整数,当整数长度Len>=17时,double会丢失末尾Len-16长度的数据精度。

   现在假设:将长度为LenP的整数P读入double类型变量时P丢失了数据精度(为此必须有LenP>=17)使得P减小(使得P增大时同证)。

   然后再设:P减小的数值为DetP,则有DetP<=10^(LenP-16)。


   POJ2109:Power of Cryptography_第1张图片


   现在计算:DetK = P^( 1 / N )- ( P - DetP )^( 1 / N )(即计算double保存P所导致的精度损失对答案的影响程度)。

   由图可知:DetK = P^( 1 / N )- ( P DetP )^( 1 / N ) ( P - ( P - DetP ) )× tanA                    

                                                        < ( P - ( P- DetP ) )× tanB

                                                         DetP× ( 1 / N )× ( P^( 1 / N - 1 ) )  

                                                          DetP× ( 1 / N )× ( P^( 1 / N ) / P )

                                                         ( DetP× K ) / ( N× P )

                                                        ≤ ( 10^( LenP - 16 ) ) / ( 10^LenP ) × ( K / N )

                                                        10^-16× ( K / P )

                                                        10^-16× ( 10^9 / 200 )

                                                        2× 10^-7

    得出结论:DetK < 2× 10^-7。

    所以可知:double保存P所导致的精度损失对答案的影响程度完全可以忽略不计!

    测试数据:16  ^  25   1267650600228229401496703205376 

              100 ^  25   6223015277861141707144064053780124240590252168721167133101116614789698834035383441183944

                            8231257136169569665895551224821247160434722900390625

              25  ^ 123   17685925284953355608333258649989090388842388168292443

              16  ^  89   154967314251789364350993277305


              POJ2109:Power of Cryptography_第2张图片

              

     测试结果:与推导结果基本吻合,P的精度损失极小,甚至于使得double无法表示出这个误差。


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


二、高精度运算+二分查找+快速幂:

   

    注意:输入数据中存在使得P^(1/N)为小数的(N,P)整数对,此时答案需要向下取整(这才是真坑所在)。

    

    首先可令:LenP为整数P的长度。

    显然可知:10^(LenP-1)     <= P       < 10^LenP。    

    那么可得:10^((LenP-1)/N) <= P^(1/N) < 10^(LenP/N)。

    所得即为:10^((LenP-1)/N) <= K       < 10^(LenP/N)。

    故而可以:在所得区间内二分查找K。


=======================================代码=======================================


一、Double And Power。




#include<math.h>
#include<stdio.h>

double n,m;

int main()
{
	while(scanf("%lf%lf",&n,&m)==2) 
	{
		printf("%.0lf\n",pow(m,1/n));
	}
}


二、高精度运算+二分查找+快速幂。



#include<math.h>
#include<stdio.h>
#include<string.h>

const int MAXLEN=1005;

int N;

char P[MAXLEN];

int BigNumCmp(char *A,char *B)                            //比较大数A和B:注意程序是逆序保存大数的!
{
	int i,LastDifVal=0;
	for(i=0;A[i]&&B[i];++i)
	{
		if(A[i]!=B[i]) { LastDifVal=A[i]-B[i]; }          
	}
	return (A[i]||B[i])?(A[i]-B[i]):(LastDifVal);         
}

char * BigNumMultipAnd(char *A,char *B)                   //大数乘赋值:A*=B
{
	char P[MAXLEN];                                       
	memset(P,0,sizeof(P));
	int EndOfP;
	for(int i=0;A[i];++i) if(A[i]!='0')                   //计算乘积:P=A*B            
	{
		for(int j=0;B[j];++j) if(B[j]!='0')
		{
			if((P[i+j]+=(A[i]-'0')*(B[j]-'0'))>=10)       
			{ 
				P[i+j+1]+=P[i+j]/10;  P[i+j]%=10;
			}
			if(!A[i+1]&&!B[j+1])                          //判断乘积终端
			{
				EndOfP=(i+j)+(P[i+j+1]!=0);
			}
		}
	}
	for(A[EndOfP+1]=0;EndOfP>=0;--EndOfP)                 //赋值乘积:A=P
	{
		A[EndOfP]=P[EndOfP]+'0';
	}
	return A;
}

char * BigNumQuickPower(int A,int B,char* R)              //大数快速幂
{
    R[0]='1'; R[1]=0;
	char Base[MAXLEN];
    for(int i=0;A;++i)                                    //将A转换为逆序大数
	{
		Base[i]=A%10+'0';
		if(!(A/=10)) { Base[i+1]=0; }
	}  
	while(B)                                             
	{
		if(B&1)   { BigNumMultipAnd(R,Base); }
		if(B>>=1) { BigNumMultipAnd(Base,Base); }
	}
	return R;
}

int BinaryChop()                                          //二分查找
{
	int LenP=strlen(P);
	int MinK=pow(10,(double)(LenP-1)/N);                  //剪枝二分上限
	int MaxK=pow(10,(double)(LenP  )/N);                  //剪枝二分下限                    
	char SaveData[MAXLEN];
	for(int i=0;i<LenP-i-1;++i)                           //逆序P以与程序中的大数保持一致
	{
		char Keep=P[i];  P[i]=P[LenP-i-1];  P[LenP-i-1]=Keep;
	}
	while(MinK<=MaxK)                                     
	{
		int MidK=((MinK+MaxK)>>1);
		int Cmp=BigNumCmp(BigNumQuickPower(MidK,N,SaveData),P);
		if(Cmp==0)   { return MidK; }                     //存在有整数K使得K^N=P:返回K
		else if(Cmp>0) { MaxK=MidK-1; } 
		else if(Cmp<0) { MinK=MidK+1; }
	}
	return MinK-1;                                        //不存在整数K使得K^N=P:对答案向下取整
}

int main()
{
	while(scanf("%d%s",&N,P)==2)
	{
		printf("%d\n",BinaryChop());
	}
	return 0;
}

你可能感兴趣的:(数据结构,二分查找)