[2020牛客暑期多校训练营第五场] F.DPS 思维模拟

题目链接: 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为下列 ”-“ 的个数。
例如:
777
如果遇到 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/maxx50.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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值