P1553 数字反转(升级版)(洛谷)

数字反转(升级版)

题目背景

以下为原题面,仅供参考:

给定一个数,请将该数各个位上数字反转得到一个新数。

这次与 NOIp2011 普及组第一题不同的是:这个数可以是小数,分数,百分数,整数。整数反转是将所有数位对调;小数反转是把整数部分的数反转,再将小数部分的数反转,不交换整数部分与小数部分;分数反转是把分母的数反转,再把分子的数反转,不交换分子与分母;百分数的分子一定是整数,百分数只改变数字部分。整数新数也应满足整数的常见形式,即除非给定的原数为零,否则反转后得到的新数的最高位数字不应为零;小数新数的末尾不为 0 0 0(除非小数部分除了 0 0 0 没有别的数,那么只保留1个 0 0 0);分数不约分,分子和分母都不是小数(约分滴童鞋抱歉了,不能过哦。输入数据保证分母不为 0 0 0),本次没有负数。

题目描述

给定一个数,请将该数各个位上数字反转得到一个新数。

这次与 NOIp2011 普及组第一题不同的是:这个数可以是小数,分数,百分数,整数。

  • 整数反转是将所有数位对调。

  • 小数反转是把整数部分的数反转,再将小数部分的数反转,不交换整数部分与小数部分。

  • 分数反转是把分母的数反转,再把分子的数反转,不交换分子与分母。

  • 百分数的分子一定是整数,百分数只改变数字部分。

输入格式

一个实数 s s s

输出格式

一个实数,即 s s s 的反转数

样例 #1

样例输入 #1

5087462

样例输出 #1

2647805

样例 #2

样例输入 #2

600.084

样例输出 #2

6.48

样例 #3

样例输入 #3

700/27

样例输出 #3

7/72

样例 #4

样例输入 #4

8670%

样例输出 #4

768%

提示

【数据范围】

  • 对于 25 % 25\% 25% 的数据, s s s 是整数,不大于 20 20 20 位;
  • 对于 25 % 25\% 25% 的数据, s s s 是小数,整数部分和小数部分均不大于 10 10 10 位;
  • 对于 25 % 25\% 25% 的数据, s s s 是分数,分子和分母均不大于 10 10 10 位;
  • 对于 25 % 25\% 25% 的数据, s s s 是百分数,分子不大于 19 19 19 位。

【数据保证】

  • 对于整数翻转而言,整数原数和整数新数满足整数的常见形式,即除非给定的原数为零,否则反转后得到的新数和原来的数字的最高位数字不应为零。

  • 对于小数翻转而言,其小数点前面部分同上,小数点后面部分的形式,保证满足小数的常见形式,也就是末尾没有多余的 0 0 0(小数部分除了 0 0 0 没有别的数,那么只保留 1 1 1 0 0 0。若反转之后末尾数字出现 0 0 0,请省略多余的 0 0 0

  • 对于分数翻转而言,分数不约分,分子和分母都不是小数。输入的分母不为 0 0 0。与整数翻转相关规定见上。

  • 对于百分数翻转而言,见与整数翻转相关内容。

数据不存在负数。

模拟

#include<bits/stdc++.h> // 引入标准库,提供各种功能的支持
using namespace std; // 使用标准命名空间

int main() {
    string a; // 定义一个字符串变量,用于存储输入的数字
    cin >> a; // 从标准输入读取一个字符串

    vector<char> s(a.begin(), a.end()); // 将字符串转换为字符向量
    int flag = 0; // 标志位,用于判断输入是哪种类型的数字
    int k = 0; // 用于标记小数点或分数线在字符串中的位置

    // 检查最后一个字符是否为百分号,如果是,则处理百分数
    if (s.back() == '%') {
        reverse(s.begin(), s.end() - 1); // 反转除百分号外的所有字符
        // 移除前导零并处理特殊情况
        for (int i = 0; i < s.size() - 1; i++) {
            if (s[i] != '0')
                break;
            if (i == s.size() - 2 && s[i] == '0') {
                cout << "0%"; // 如果整个数字部分都是0,则输出0%
                return 0;
            }
        }
        int i = 0;
        while (s[i] == '0') i++; // 跳过前导零
        for (; i < s.size(); i++) // 输出反转后的数字部分
            cout << s[i];
        return 0;
    }

    // 遍历字符串,查找小数点或分数线的位置
    for (int i = 0; i < s.size(); i++) {
        if (s[i] == '.') {
            flag = 1; // 标记为小数
            k = i; // 记录小数点的位置
            break;
        }
        if (s[i] == '/') {
            flag = 2; // 标记为分数
            k = i; // 记录分数线的位置
            break;
        }
    }

    // 根据标志位处理不同类型的数字反转
    if (flag == 1) { // 小数
        // 处理整数部分
        vector<char> q(a.begin(), a.begin() + k);
        // 反转整数部分并移除末尾零
        for (int i = 0; i < q.size(); i++) {
            if (q[i] != '0')
                break;
            if (i == q.size() - 1 && q[i] == '0') {
                cout << "0";
            }
        }
        while (q.size() > 0 && q.back() == '0') q.pop_back();
        reverse(q.begin(), q.end()); // 反转整数部分
        // 输出整数部分
        for (int i = 0; i < q.size(); i++)
            cout << q[i];
        cout << '.'; // 输出小数点
        // 处理小数部分
        vector<char> h(a.begin() + k + 1, a.end());
        for (int i = 0; i < h.size(); i++) {
            if (h[i] != '0')
                break;
            if (i == h.size() - 1 && h[i] == '0') {
                cout << '0';
                return 0;
            }
        }
        reverse(h.begin(), h.end()); // 反转小数部分
        while (h.size() > 0 && h.back() == '0') h.pop_back();
        // 输出小数部分
        for (int i = 0; i < h.size(); i++)
            cout << h[i];
    } else if (flag == 2) { // 分数
        // 处理分子部分
        vector<char> q(a.begin(), a.begin() + k);
        // 反转分子部分并移除末尾零
        for (int i = 0; i < q.size(); i++) {
            if (q[i] != '0')
                break;
            if (i == q.size() - 1 && q[i] == '0') {
                cout << "0";
            }
        }
        while (q.size() > 0 && q.back() == '0') q.pop_back();
        reverse(q.begin(), q.end()); // 反转分子部分
        // 输出分子部分
        for (int i = 0; i < q.size(); i++)
            cout << q[i];
        cout << '/'; // 输出分数线
        // 处理分母部分
        vector<char> h(a.begin() + k + 1, a.end());
        while (h.size() > 0 && h.back() == '0') h.pop_back(); // 移除末尾零
        reverse(h.begin(), h.end()); // 反转分母部分
        // 输出分母部分
        for (int i = 0; i < h.size(); i++)
            cout << h[i];
    } else { // 整数
        // 反转整数部分并移除前导零
        for (int i = 0; i < s.size(); i++) {
            if (s[i] != '0')
                break;
            if (i == s.size() - 1 && s[i] == '0') {
                cout << "0";
            }
        }
        while (s.size() > 0 && s.back() == '0') s.pop_back();
        reverse(s.begin(), s.end()); // 反转整数部分
        // 输出整数部分
        for (int i = 0; i < s.size(); i++)
            cout << s[i];
    }
    return 0; // 程序结束
}

代码的主要逻辑是首先根据输入的数字类型(整数、小数、分数、百分数)进行分类处理,然后对每个部分进行反转,最后输出反转后的数字。在处理小数和分数时,特别注意了前导零和末尾零的处理,以符合题目要求的数字表示形式。

踩到的坑

  • 当我在处理末尾0时,我使用了while (s.size() > 0 && s.back() == '0') s.pop_back();,如果当该部分只有0时,例如0,0.123,0/56,0%,会把0删掉
  • 小数部分的反转逻辑和其他部分略微不一样,例如0.056我一开始反转成了0.560,这是因为我在反转前先处理了末尾0,例如0.560先变为0.56,在反转为0.65,但这是错误的,0.056是正确的,所以我先反转,在处理末尾0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

命运从未公平

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值