数位之和-B4036 [GESP202409 二级]

题目描述

小杨有 n 个正整数,他认为一个正整数是美丽数字当且仅当该正整数每一位数字的总和是 7 的倍数。

小杨想请你编写一个程序判断 n 个正整数哪些是美丽数字。

输入格式

第一行包含一个正整数 n,表示正整数个数。
之后 n 行,每行一个包含一个正整数 ai​。

输出格式

对于每个正整数输出一行一个字符串,如果是美丽数字则输出 Yes,否则输出 No

输入输出样例

说明/提示

数据规模与约定

对全部的测试数据,保证 1≤n≤105,1≤ai​≤105。

B4036 [GESP202409 二级] 数位之和 - 洛谷

同类问题分析

这一题同上一篇的【计数】,都属于数位处理问题,在解题思路、代码实现和优化方法上有许多相通之处。以下是它们的核心相通点和关联分析:

1. 问题本质相通

  • 都需要分解数字的每一位:无论是计算数位之和还是统计特定数字出现的次数,都需要通过循环或数学方法分解数字的各位(个位、十位、百位等)。

  • 核心操作一致:通过 %10 取最低位,/10 去掉最低位,是两类问题的通用操作。

// 数位之和
int sum = 0;
while (n > 0) {
    sum += n % 10;  // 取当前位并累加
    n /= 10;        // 去掉当前位
}

// 数字计数
int count = 0;
while (n > 0) {
    if (n % 10 == k) count++;  // 检查当前位是否为目标数字
    n /= 10;
}

2. 暴力解法的相似性

  • 双重循环结构:两类问题通常都需要外层循环遍历数字范围(1到n),内层循环分解每个数字的各位。

  • 时间复杂度相近:均为 O(n * log n)(因为每个数字的位数约为 log₁₀n)。

for (int i = 1; i <= n; i++) { // 外层:遍历数字

    int t = i;

    while (t > 0) { // 内层:分解各位 

         // 数位之和:sum += t % 10;

        // 数字计数:if (t % 10 == k)  cnt++;

        t /= 10;

   }

}

代码实现

#include <iostream>
using namespace std;
int main(){
    int n;cin>>n;
    int a,sum;
    while(n--){
        cin>>a;sum=0;
        while(a){
            sum+=a%10;
            a/=10;
        }
        cout<<(sum%7==0?"Yes":"No")<<endl;
    }
}

扩展题目(举一反三)

1、统计奇数位数字之和与偶数位数字之和的差。

要统计一个整数中奇数位数字之和与偶数位数字之和的差,我们需要明确位数的奇偶定义。通常有两种定义方式:

  • 从右向左(低位到高位)编号:个位为第1位(奇数位),十位为第2位(偶数位),以此类推。
  • 从左向右(高位到低位)编号:最高位为第1位(奇数位),次高位为第2位(偶数位),以此类推。

以下代码采用从右向左编号的方式(个位为奇数位),用暴力枚举解法如下:

#include <iostream>
using namespace std;

int digitSumDifference(int n) {
    int oddSum = 0, evenSum = 0;
    int position = 1; // 从个位开始,position=1表示奇数位
    
    while (n > 0) {
        int digit = n % 10;
        if (position % 2 == 1) {
            oddSum += digit; // 奇数位
        } else {
            evenSum += digit; // 偶数位
        }
        n /= 10;
        position++;
    }
    
    return oddSum - evenSum;
}

int main() {
    int num;
    cin >> num;
    cout << digitSumDifference(num) << endl;
    return 0;
}

2、计算回文数字的数量。

回文数字是指正读和反读都相同的数字,例如121、1331等。

#include <iostream>
using namespace std;

bool isPalindrome(int num) {
    if (num < 0) return false; // 负数不是回文数
    if (num < 10) return true; // 个位数是回文数
    
    int original = num;
    long reversed = 0; // 使用long防止反转后溢出
    
    while (num > 0) {
        reversed = reversed * 10 + num % 10;
        num /= 10;
    }
    
    return original == reversed;
}

int main() {
    int num;
    cin >> num;
    cout << (isPalindrome(num) ? "Yes" : "No") << endl;
    return 0;
}

3、统计数字中某两个相邻数字满足特定条件(如递增)的次数。

  • 分解数字各位:使用 %10 和 /10 操作获取数字的每一位
  • 比较相邻数字:保存前一位数字,与当前位比较
  • 统计满足条件的情况:根据比较结果进行计数

比如,统计递增相邻对,代码如下:

#include <iostream>
using namespace std;

int countIncreasingPairs(int num) {
    if (num < 10) return 0; // 单个数字无相邻对
    
    int count = 0;
    int prevDigit = num % 10;
    num /= 10;
    
    while (num > 0) {
        int currDigit = num % 10;
        if (currDigit < prevDigit) { // 前一位大于当前位,即数字顺序是递增的
            count++;
        }
        prevDigit = currDigit;
        num /= 10;
    }
    
    return count;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

智码行者

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

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

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

打赏作者

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

抵扣说明:

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

余额充值