hdoj 3750
http://acm.hdu.edu.cn/showproblem.php?pid=3750
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 254 Accepted Submission(s): 143
菜鸟杯上的一道题
我当时直接按照期望的定义来做的 递归的代码
比赛的时候一直错
很无语 而且浪费了很多时间
现在终于法相当时错的原因了 有点想砍人的冲动……
不过因为这个我学到了一个技巧。
首先说明:
在做要求保留精度的题时 原则是能先整数运算尽量整数运算 最后再四舍五入保留小数。
下面是技巧
比如这题
经过我对此题深入的一番研究
发现:
当输入数据时40时
正确答案是4.57500000 保留2位小数是4.58
我的答案是4.57499999 保留2位小数是4.57
你说能不让人想砍人吗?
这题我是这样AC的
4.5749999先乘以100000-->457499.99再+0.5-->457500.49取整-->457500再除以100000-->4.57500保留2位小数输出-->4.58
这个技巧我觉得还是重要
以后遇到怀疑自己答案精度问题的题时(特别是中途四舍五入了很多次而答案又很像的题) 可以考虑这个技巧
先乘-->四舍五入-->再除回来-->四舍五入输出
当然具体乘多少看题目了
我这次乘的100000 也就是先多保留了5位小数 我试过*10但还是错
总之就是+一个很小的数
我的代码(递归中损失了不少精度 不过排名居然还更高):
#include
#define eps 1e-6
double sum;
void expect(int now,int n,double s)
{
int d=n/2;
if(n==0) return;
sum+=s*now/n;
s=s*(1-1.0/n);
if(n%2)
expect(now+1,d,s);
else
{
expect(now+1,d,s*d/(n-1));
expect(now+1,d-1,s*(d-1)/(n-1));
}
}
int main()
{
int n,s;
while(~scanf("%d",&n))
{
sum=0.0;
expect(1,n,1.0);
printf("%.2lf\n",sum+eps);
}
return 0;
}
其它的代码:(同学给我的 没看懂...)
#include
int main()
{
int n,t,s,i,m;
while(~scanf("%d",&n))
{
t=1;
s=0;
m=n;
for(i=1;n>t;i++)
{
s+=i*t;
n-=t;
t*=2;
}
s+=n*i;
printf("%d--->%.2lfn",n,(double)1.0*s/m);
}
return 0;
}