题目链接: F.DPS
又是一个雷声大雨点小的题,看来题不可貌相啊。一看输出又双叒叕以为是一个难题,没想到是第二个签到题,但这个签到签到的并不怎么成功。
题意
题目大意是输入n个数,然后按照要求输出相应的图案。
题目给了一个公式:
s
i
=
⌈
50
d
i
m
a
x
i
d
i
⌉
{s_i= \lceil 50\frac{d_i}{max_id_i}\rceil }
si=⌈50maxididi⌉,大意就是这个数除以n个数里最大的数然后乘上50向上取整。
得到的这个
s
i
{s_i}
si为下列 ”-“ 的个数。
例如:
如果遇到
s
i
{s_i}
si最大时,需要将中间最后一个空格替换为 ’ * '。
题解
这个题本来正常模拟就行,但我们偏偏栽在了精度问题上。
最常规的求
s
i
{s_i}
si
int t=(ll)d[i]*50;
if(t%maxx==0) t=t/maxx+1;
else t/=maxx;
还有
int t=ceil(d[i]*50.0/maxx);
但注意!!!
t
=
c
e
i
l
(
d
[
i
]
∗
1.0
/
m
a
x
x
∗
50.0
)
;
{ \cancel{t=ceil(d[i]*1.0/maxx*50.0);}}
t=ceil(d[i]∗1.0/maxx∗50.0);
本来以为先除后乘能避免爆long long,但谁知道在这样会损失精度。
我写了一个测试代码
int main()
{
int maxx;
cin >> maxx;
for(int i=1;i<=maxx;i++)
{
int r1=ceil(i*50.0/maxx);
int r2=ceil(i*1.0/maxx*50.0);
if(r1!=r2)
{
cout << "find!" << endl;
cout << i << endl;
printf("%d %d\n",r1,r2);
}
}
}
以d[i]最大范围值43962200为例,发现的确存在精度损失。
以i为6154708为例,
int main()
{
int maxx=43962200,i;
i=6154708;
int r1=ceil(i*50.0/maxx);
int r2=ceil(i*1.0/maxx*50.0);
printf("%.15lf\n",(i*1.0)/maxx);
printf("%.15lf\n",(i*1.0)/maxx*50);
}
结果:
发现0.14*50出现精度错误!!
(i*0.1)后会转换为double类型,而double类型有效数字16位,16位以后可能会出现精度偏差,所以会出现结果7.000000000000001!=7的情况,进而导致向上取整出现错误。
所以综上所述,不能先除后乘。
代码
ll d[205];
int main()
{
int n;
cin >> n;
ll maxx=-1;
for(int i=0;i<n;i++)
{
cin >> d[i];
maxx=max(maxx,d[i]);
}
for(int i=0;i<n;i++)
{
int r=ceil((d[i]*50.0)/maxx);
cout << "+";
for(int j=0;j<r;j++) cout << "-";
cout << "+" << endl;
cout << "|";
if(d[i]==maxx)
{
for(int j=0;j<r-1;j++) cout << " " ;
cout << "*|" << d[i] << endl;
}
else {
for(int j=0;j<r;j++) cout << " " ;
cout << "|" << d[i] << endl;
}
cout << "+";
for(int j=0;j<r;j++) cout << "-";
cout << "+" << endl;
}
}