POJ 2109 Power of Cryptography二分+大数相乘和pow为什么可以直接过的原因
2013-07-28 17:18
423 查看
http://poj.org/problem?id=2109
这个题目一看就是个大数的题目,但是很流行下面这段一行代码的程序:
#include<stdio.h>
#include<math.h>
#include<iostream>
using namespace std;
int main()
{
double a,b;
while(cin>>a>>b)
{
cout<<pow(b,1.0/a)<<endl;
}
return 0;
}
虽然这段代码经过无数次提交ac的证明,但是我不得不说,不懂,完全不懂,double 能把100位的n按照合理精度转下来吗?、、
也许这个代码能够ac,是因为测试数据不严谨吧。
先介绍正解,然后在说明原因。
下面,介绍正解:
二分+大数运算
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
using namespace std;
#define M 400
#define mem0(f) memset(f,0,sizeof(f))
//先写大数相乘
char res[M],nn[M];
int k;
void times(char*a,char*b,char*s)
{
char aa[M],bb[M];
mem0(aa);
mem0(bb);
int l1=strlen(a),l2=strlen(b);
for(int i=0;i<l1;i++)
{
aa[i]=a[l1-i-1]-'0';
}
for(int i=0;i<l2;i++)
{
bb[i]=b[l2-1-i]-'0';
}
int n=0;
for(int i=0;i<l1;i++)
{
n=i;
for(int k=0;k<l2;k++)
{
s
+=aa[i]*bb[k];
if(s
>9)
{
s[n+1]+=s
/10;
s
=s
%10;
}
n++;
}
}
if(s
)n++;
for(int i=0;i<n;i++)
{
s[i]+='0';
}
char t;
for(int i=0;2*i<n;i++)
{
t=s[i];
s[i]=s[n-1-i];
s[n-i-1]=t;
}
}
void power(char*a,int n,char*s)
{
char sm[M];
strcpy(s,"1");
for(int i=0;i<n;i++)
{
mem0(sm);
//cout<<n<<endl;
times(s,a,sm);
strcpy(s,sm);
//puts(s);
}
//strcpy(s,sm);
}
int cmp(char*a,char*b)
{
int l1=strlen(a),l2=strlen(b);
if(l1>l2)return 1;
else if(l1<l2)return -1;
else
{
for(int i=0;i<l1;i++)
{
if(a[i]>b[i])return 1;
else if(a[i]<b[i])return -1;
}
return 0;
}
}
int minn,maxx,n,ok,cen;
char mid[M];
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while(~scanf("%d%s",&k,nn))
{
ok=0;
mem0(mid);
mem0(res);
n=ceil(((float)strlen(nn)/k));
//puts(nn);
minn=(int)pow(10,n-1);
maxx=(int)pow(10,n)-1;
//cen=(minn+maxx)/2;
while(!ok)
{
mem0(res);
mem0(mid);
cen=(minn+maxx)/2;
sprintf(mid,"%d",cen);
power(mid,k,res);
if(cmp(res,nn)<0)
{
minn=cen+1;
}
else if(cmp(res,nn)>0)
{
maxx=cen-1;
}
else
{
ok=1;
}
if(minn>maxx)break;
}
//这个题目说总会存在k是逗我们玩的,其实就是找满足k的p次方小于或等于n的最大k值,这也是为什么pow可以直接过的原因之一。
//如果没有下面在无解时的近似处理,结果是WA,实验过了,加上这段代码的话就可以AC,果断测试数据坑人有木有!
if(!ok)
{
while(cmp(res,nn)>0)
{
cen--;
sprintf(mid,"%d",cen);
mem0(res);
power(mid,k,res);
}
}
printf("%d\n",cen);
}
return 0;
}
上面对代码的说明解释了pow可以直接过的部分原因:反正是要求一个最大值,根本就不需要存储所有的精度。
深层分析如下
首先,题目中的数据强度并不弱,这一点确实如题目中所说:“For all such pairs 1<=n<= 200, 1<=p<10101,所以,double型是不能精确地表示出所给数据,但是却能表示出一个近似值。
当向double型变量中存入
4357186184021382204544
然后再输出,得到的是
4357186184021382000000
后六位的值变为了0,这一点和int型变量是有很大区别的。也就是说当存入double型变量的值超出了它的精度表示范围时,将低位的数据截断。(关于浮点数在计算机中的表示方法,百度吧…讲的蛮清楚的。)
在本题中,如果测试数据为:
7 4357186184021382204544
实际上所处理数据是:
7 4357186184021382000000
拿4357186184021382000000开7次方的结果自然就是1234。
为什么不是1233或者1235呢?
12337=4332529576639313702577
12347=4357186184021382204544
12357=4381962969567270546875
可以看出在double型所能表示的精度范围内,它们三个值已经不同了。
所以,此题中的测试数据也都是类似于上述情况,所以才能使用double型开n次方的方法。
关于此,感谢
CSDN的PangWD_C,
更多及原文请访问http://blog.csdn.net/code_pang/article/details/8263971
这个题目一看就是个大数的题目,但是很流行下面这段一行代码的程序:
#include<stdio.h>
#include<math.h>
#include<iostream>
using namespace std;
int main()
{
double a,b;
while(cin>>a>>b)
{
cout<<pow(b,1.0/a)<<endl;
}
return 0;
}
虽然这段代码经过无数次提交ac的证明,但是我不得不说,不懂,完全不懂,double 能把100位的n按照合理精度转下来吗?、、
也许这个代码能够ac,是因为测试数据不严谨吧。
先介绍正解,然后在说明原因。
下面,介绍正解:
二分+大数运算
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
using namespace std;
#define M 400
#define mem0(f) memset(f,0,sizeof(f))
//先写大数相乘
char res[M],nn[M];
int k;
void times(char*a,char*b,char*s)
{
char aa[M],bb[M];
mem0(aa);
mem0(bb);
int l1=strlen(a),l2=strlen(b);
for(int i=0;i<l1;i++)
{
aa[i]=a[l1-i-1]-'0';
}
for(int i=0;i<l2;i++)
{
bb[i]=b[l2-1-i]-'0';
}
int n=0;
for(int i=0;i<l1;i++)
{
n=i;
for(int k=0;k<l2;k++)
{
s
+=aa[i]*bb[k];
if(s
>9)
{
s[n+1]+=s
/10;
s
=s
%10;
}
n++;
}
}
if(s
)n++;
for(int i=0;i<n;i++)
{
s[i]+='0';
}
char t;
for(int i=0;2*i<n;i++)
{
t=s[i];
s[i]=s[n-1-i];
s[n-i-1]=t;
}
}
void power(char*a,int n,char*s)
{
char sm[M];
strcpy(s,"1");
for(int i=0;i<n;i++)
{
mem0(sm);
//cout<<n<<endl;
times(s,a,sm);
strcpy(s,sm);
//puts(s);
}
//strcpy(s,sm);
}
int cmp(char*a,char*b)
{
int l1=strlen(a),l2=strlen(b);
if(l1>l2)return 1;
else if(l1<l2)return -1;
else
{
for(int i=0;i<l1;i++)
{
if(a[i]>b[i])return 1;
else if(a[i]<b[i])return -1;
}
return 0;
}
}
int minn,maxx,n,ok,cen;
char mid[M];
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while(~scanf("%d%s",&k,nn))
{
ok=0;
mem0(mid);
mem0(res);
n=ceil(((float)strlen(nn)/k));
//puts(nn);
minn=(int)pow(10,n-1);
maxx=(int)pow(10,n)-1;
//cen=(minn+maxx)/2;
while(!ok)
{
mem0(res);
mem0(mid);
cen=(minn+maxx)/2;
sprintf(mid,"%d",cen);
power(mid,k,res);
if(cmp(res,nn)<0)
{
minn=cen+1;
}
else if(cmp(res,nn)>0)
{
maxx=cen-1;
}
else
{
ok=1;
}
if(minn>maxx)break;
}
//这个题目说总会存在k是逗我们玩的,其实就是找满足k的p次方小于或等于n的最大k值,这也是为什么pow可以直接过的原因之一。
//如果没有下面在无解时的近似处理,结果是WA,实验过了,加上这段代码的话就可以AC,果断测试数据坑人有木有!
if(!ok)
{
while(cmp(res,nn)>0)
{
cen--;
sprintf(mid,"%d",cen);
mem0(res);
power(mid,k,res);
}
}
printf("%d\n",cen);
}
return 0;
}
上面对代码的说明解释了pow可以直接过的部分原因:反正是要求一个最大值,根本就不需要存储所有的精度。
深层分析如下
首先,题目中的数据强度并不弱,这一点确实如题目中所说:“For all such pairs 1<=n<= 200, 1<=p<10101,所以,double型是不能精确地表示出所给数据,但是却能表示出一个近似值。
当向double型变量中存入
4357186184021382204544
然后再输出,得到的是
4357186184021382000000
后六位的值变为了0,这一点和int型变量是有很大区别的。也就是说当存入double型变量的值超出了它的精度表示范围时,将低位的数据截断。(关于浮点数在计算机中的表示方法,百度吧…讲的蛮清楚的。)
在本题中,如果测试数据为:
7 4357186184021382204544
实际上所处理数据是:
7 4357186184021382000000
拿4357186184021382000000开7次方的结果自然就是1234。
为什么不是1233或者1235呢?
12337=4332529576639313702577
12347=4357186184021382204544
12357=4381962969567270546875
可以看出在double型所能表示的精度范围内,它们三个值已经不同了。
所以,此题中的测试数据也都是类似于上述情况,所以才能使用double型开n次方的方法。
关于此,感谢
CSDN的PangWD_C,
更多及原文请访问http://blog.csdn.net/code_pang/article/details/8263971
相关文章推荐
- POJ Round and Round We Go(核心大数相乘算法)
- 为什么直接执行shell脚本可以,但crontab下执行错误
- caffe小问题汇总(持续更新) PS:所有问题均在caffe-windows下产生 1、为什么AlexNet中,InnerProduct_Layer(fc8)层的输出可以直接作为Accuracy
- POJ 1014 不明白为什么数据可以缩小到60跟61
- InetAddress为什么不能new而可以直接拿来用
- 为什么直接执行shell脚本可以,但crontab下执行错误
- 为什么连接时候可以直接调用储存过程,而没有事先声明
- 【Android问题记录】为什么在终端直接查询数据库可以查到数据但是用代码总是查不到
- static方法可以直接从普通方法(regular method)中调用,但是普通方法不能直接从static方法中调用,为什么?
- poj 2109 二分+大数乘法
- 刚安装好的TD为什么不用输入密码就可以直接的login的解答
- 如题,既然直接对一个实例发送方法名就可以调用这个方法,那为什么还要使用performSelector:去调呢?两者u有啥区别
- POJ推荐50题 1. 标记“难”和“稍难”的题目可以看看,思考一下,不做要求,当然有能力的同学可以直接切掉。 2. 标记为 A and B 的题目是比较相似的题目,建议大家两个一起做,可以对比总结,
- 关于为什么整型不能和float,double型直接比较大小的原因
- 有错误先找自己的原因(若你百度不出为什么vista开网页慢,可以来试试这方法)
- 为什么mysql having的条件表达式可以直接使用select后的别名?
- POJ 2109 少见多怪,利用double log pow 解决高精度
- POJ2389大数相乘
- 为什么还需要邮件服务器 直接使用企业邮箱不使用邮件服务器是否可以
- 为什么CRect可以直接转LPCRECT?