1104、天长地久 PAT乙级

文章描述了一个编程问题,要求找到满足特定条件的正整数(天长地久数),即数字和与其加1后的数字和的最大公约数是大于2的素数。文章提供了输入输出格式、代码示例和解题思路,包括使用打表法和结构体进行处理,并通过排序找到所有可能的解。
摘要由CSDN通过智能技术生成

1104、天长地久

题目描述

  • “天长地久数”是指一个 K 位正整数 A,其满足条件为:A 的各位数字之和为 mA+1 的各位数字之和为 n,且 mn 的最大公约数是一个大于 2 的素数。本题就请你找出这些天长地久数。

输入输出格式

输入格式:

  • 输入在第一行给出正整数 N(≤5),随后 N 行,每行给出一对 K(3<K<10)和 m(1<m<90),其含义如题面所述。

输出格式:

  • 对每一对输入的 Km,首先在一行中输出 Case X,其中 X 是输出的编号(从 1 开始);然后一行输出对应的 nA,数字间以空格分隔。如果解不唯一,则每组解占一行,按 n 的递增序输出;若仍不唯一,则按 A 的递增序输出。若解不存在,则在一行中输出 No Solution

输入输出样式

输入样例:
2
6 45
7 80
输出样例:
Case 1
10 189999
10 279999
10 369999
10 459999
10 549999
10 639999
10 729999
10 819999
10 909999
Case 2
No Solution

题目分析

注释写的够详细了,自己看,另外再次表白柳神

代码示例

//此为打表观察法,由打表观察法易知最后两位恒为99
//ps(当时看柳神代码看的一脸懵逼,打表?是什么东西?)
#include <iostream>
#include <string>
using namespace std;
//取数各项之和
int getNum(long long num) {
    int sum = 0;
    while (num) {
        sum += num % 10;
        num /= 10;
    }
    return sum;
}
//取两个数公约数
int get(int x, int y) {
    int z = y;
    while (x%y != 0){
        z = x % y,x = y,y = z;
    }
    return z;
}
//判断是否为素数
bool IsPrime(int number) {
    if (number <= 2) return false; 
    for (int i = 2; i <= number / 2; i++) 
        if (number%i == 0) return false;
    return true;
}
​
int main() {
    //开始打表
    for (long long i = 10000; i < 999999999; i++) {
        int number = get(getNum(i), getNum(i + 1));
        if (IsPrime(number)) cout << i << endl;
    }
    return 0;
}
//此为AC代码,个人认为这是笔者写PAT乙到现在最复杂的题目,从来没有写代码超过50行
#include <iostream>
#include <string>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
​
//因为要比较大小,所以我们先建立一个结构体
struct Node {
    int n, num;
    //struct的属性是public但是它的方法可是private这里我们搞一个友元让方法可以被外部访问
    /*参数类型如果是自定义类型,比如自己定义的结构体,类,
    尽管sort函数默认是从小到大排列,但是这里必须要重载比较运算符“ < ”!!!*/
    friend bool operator < (Node &a, Node &b) {
        if (a.n != b.n) return a.n < b.n;
        else return a.num < b.num;
    }
};
​
//判断是否是大于2的素数
bool Is_Prime(int num) {
    if (num <= 2) return false;
    for (int i = 2; i <= sqrt(num); i++)
        if (num%i == 0) return false;
    return true;
}
​
//求两个数的最大公约数
int Get_Number(int num1, int num2) {
    int number = num2;
    while (num1%num2 != 0) {
        number = num1 % num2, num1 = num2, num2 = number;
    }
    return number;
}
​
int main() {
    int total, K, M;
    cin >> total;
    for (int i = 1; i <= total; i++) {
        vector<Node> Vec;
        cout << "Case " << i << endl;
        cin >> K >> M;
        //最大是k个9如果最大都小于M的话,那么这个数就不存在了
        if (K * 9 < M) cout << "No Solution" << endl;
        else {
            //由打表观察法我们已然得知最后两位数必为99那么我们将之省略即可
            int temp = pow(10, K - 2);
            //注释是地方是柳神原来的i=temp/10但是我没有看懂,为什么前面的都被排除了,所以我改成了10
            for (int i = /*temp / */10; i <= temp; i++) {
                int sum1 = 18, sum2 = 0, A = i, A1 = i + 1;
                while (A) {
                    sum1 += A % 10;
                    A /= 10;
                    //sum1都比我们输入的各数之和要大了,就没有必要继续算下去了
                    if (sum1 > M) break;
                }
                while (A1) {
                    sum2 += A1 % 10, A1 /= 10;
                }
                if (sum1 == M && Is_Prime(Get_Number(sum1, sum2))) {
                    Node node = { sum2,i };
                    Vec.push_back(node);
                }
            }
            sort(Vec.begin(), Vec.end());
            if (Vec.empty()) cout << "No Solution" << endl;
            else {
                for (auto it = Vec.begin(); it != Vec.end(); it++)
                    cout << it->n << " " << it->num << "99" << endl;
            }
        }
    }
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值