POJ 2109 -- Power of Cryptography
Power of Cryptography
Time Limit: 1000MS | Memory Limit: 30000K | |
Total Submissions: 26622 | Accepted: 13301 |
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 nth. power, for an integer k (this integer is what your program must find).
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 nth. 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<10101 and there exists an integer k, 1<=k<=109 such that kn = 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
题意:
求一个整数k,使得k满足kn=p。
题意分析:
1)
1<=n<= 200, 1<=p<10101 ,1<=k<=109 , kn = p.
最直观的解题思路是使用 高精度算法,但是这道题可以使用double巧妙地避开。
用pow函数求解:
k = pow(p, 1.0/n)
double的取值范围为10^(-307)~10^308,但小数精度只有前16位, 其误差范围在10^(-15)的数量级左右.
这个误差级数仅会对n的小数部分存在影响,四舍五入后对整数部分是无影响的.
而题目已经限定了,n、k、p均是整数,因此使用公式法可以直接得到准确结果.
假若题目不存在整数限制,当n极大时,k会极小(无限迫近1,对小数精度极高),
此时公式法则会因为精度问题而失效.
1 #include<iostream> 2 #include<cmath> 3 using namespace std; 4 int main() 5 { 6 double n,p; 7 while(cin>>n>>p) 8 { 9 double k; 10 k = pow(p,1.0/n); 11 cout<<k<<endl;; 12 } 13 return 0; 14 }
2)使用 高精度算法 + 二分法
首先,想要求 kn = p的k,不使用如上计算方法的公式法,只能枚举k,进行高精度乘法。
寻找k的方法,可以使用二分法。
那k的范围是什么呢,考虑样例7 4357186184021382204544,p是22位,22/7=3~4,向上取整,所以p是一个四位数,即1000<=p<=9999。
在这个范围进行二分查找,就可以找到k。
关于高精度算法,看过一个博文,想了解详情的可以移步=》从零开始学算法:高精度计算
c++ / % 四舍五入 向上取整ceil 向下取整floor
1 #include<iostream> 2 #include<math.h> 3 #include<cstring> 4 #include<stdio.h> 5 using namespace std; 6 const int maxp = 104; 7 //const int maxk = 12; 8 int p[maxp]; 9 int k[maxp]; 10 11 int Compare(int a[],int b[]) 12 {///如果相等返回0,>返回1,<返回-1 13 if(a[0] > b[0]) return 1; 14 else if(a[0] < b[0]) return -1; 15 else//位数相等,需要逐位判断 16 { 17 for(int i=a[0];i>0;i--) 18 { 19 if(a[i]>b[i]) return 1; 20 else if(a[i] < b[i]) return -1; 21 } 22 } 23 return 0; 24 } 25 26 void bigEqual(int n) 27 {///计算k^n,将结果存在k中 28 int temp[maxp];int Equal[maxp]; 29 memset(Equal,0,sizeof(Equal));//用来存放另一个乘数 30 memset(temp,0,sizeof(temp));//用来存放每次相乘的结果 31 for(int i = 0;i<=k[0];i++) 32 Equal[i] = k[i]; 33 for(int turn = 1;turn<n;turn++) 34 { 35 for(int i=1;i<=k[0];i++)///计算k * Equal,存在temp中 36 { 37 for(int j=1;j<=Equal[0];j++) 38 { 39 temp[i+j-1] += k[i]*Equal[j]; 40 } 41 temp[0] = Equal[0]+k[0]-1; 42 for(int j=1;j<=temp[0];j++)///处理进位 43 { 44 if(temp[j]>=10) 45 { 46 temp[j+1] += temp[j]/10;temp[j] = temp[j]%10; 47 } 48 } 49 while(temp[temp[0]+1]) 50 { 51 temp[0]++; 52 temp[temp[0]+1] = temp[temp[0]]/10; 53 temp[temp[0]] = temp[temp[0]]%10; 54 } 55 } 56 for(int m=0;m<=temp[0];m++) 57 Equal[m] = temp[m];//转存temp作为下一次的乘数 58 memset(temp,0,sizeof(temp)); 59 } 60 for(int i=0;i<=Equal[0];i++) 61 k[i] = Equal[i]; 62 } 63 64 int main() 65 { 66 char s[maxp]; 67 int n; 68 while(scanf("%d %s",&n,&s) != EOF) 69 { 70 memset(p,0,sizeof(p)); 71 ///将p处理成数组 72 p[0] = strlen(s);//第一位存储p的位数 73 for(int i=p[0]-1;i>=0;i--) 74 { 75 p[p[0]-i] = s[i]-'0'; 76 } 77 int kLength = ceil((double)p[0]/n);//向上取整 78 int Min = 1,Max = 9; 79 for(int i=1;i<kLength;i++) 80 { 81 Min *=10; 82 } 83 for(int i=1;i<kLength;i++) 84 { 85 Max *=10;Max += 9; 86 } 87 ///使用二分法查找 88 double Mid = (Min+Max)/2; 89 for(int low = Min,up = Max;low<=up;) 90 { 91 memset(k,0,sizeof(k)); 92 ///给k赋值为Mid 93 int i=1;int temp = Mid; 94 while(temp) 95 { 96 k[i] = temp%10; 97 temp = temp/10; 98 i++; 99 } 100 k[0] = i-1;//k[0]存储k的长度 101 bigEqual(n);///计算k^n,将结果存储在k中 102 int j = Compare(k,p); 103 if(j == 0)//相等 104 break; 105 else if(j == 1)//k>p,向Mid的左侧查找 106 { 107 up = Mid-1;Mid = (low+up)/2; 108 } 109 else{//k<p,向Mid的右侧查找 110 low = Mid+1;Mid = (low+up)/2; 111 } 112 } 113 cout<<Mid<<endl; 114 } 115 return 0; 116 }
告诫自己:
s不可以用String类型
string不可以用cin>>进行赋值