CCF-GESP计算机学会等级考试2025年6月六级C++T2 最大因数

P13016 [GESP202506 六级] 最大因数

题目描述

给定一棵有 10910^9109 个结点的有根树,这些结点依次以 1,2,…,1091, 2, \dots, 10^91,2,,109 编号,根结点的编号为 111。对于编号为 kkk2≤k≤1092 \leq k \leq 10^92k109)的结点,其父结点的编号为 kkk 的因数中除 kkk 以外最大的因数。

现在有 qqq 组询问,第 iii1≤i≤q1 \leq i \leq q1iq)组询问给定 xi,yix_i, y_ixi,yi,请你求出编号分别为 xi,yix_i, y_ixi,yi 的两个结点在这棵树上的距离。两个结点之间的距离是连接这两个结点的简单路径所包含的边数。

输入格式

第一行,一个正整数 qqq,表示询问组数。

接下来 qqq 行,每行两个正整数 xi,yix_i, y_ixi,yi,表示询问结点的编号。

输出格式

输出共 qqq 行,每行一个整数,表示结点 xi,yix_i, y_ixi,yi 之间的距离。

输入输出样例 #1

输入 #1

3
1 3
2 5
4 8

输出 #1

1
2
1

输入输出样例 #2

输入 #2

1
120 650

输出 #2

9

说明/提示

对于 60%60\%60% 的测试点,保证 1≤xi,yi≤10001 \leq x_i, y_i \leq 10001xi,yi1000

对于所有测试点,保证 1≤q≤10001 \leq q \leq 10001q10001≤xi,yi≤1091 \leq x_i, y_i \leq 10^91xi,yi109

解析

要想求两个节点的最近距离,就要找到他们俩的共同祖先,详见代码:

#include <bits/stdc++.h>
using namespace std;
int q,x,y;
int f(int a){//求最大因子
    for(int i=2;i*i<=a;i++){
        if (a%i==0){
            return a/i;
        }
    }
    return 1;
}
int main(){
    cin>>q;
    while(q--){
        cin>>x>>y;
        int cnt=0;//距离
        while(x!=y){//不相等,即没到共同根
            if (x>y){//谁大,就求谁的父节点
                x=f(x);
            }else{
                y=f(y);
            }
            cnt++;//距离增加1
        }
        cout<<cnt<<"\n";
    }
	return 0;
}

加上记忆化,会更快些,其实没什么用

#include <bits/stdc++.h>
using namespace std;
int q,x,y;
map <int,int> mp;
int f(int a){//求最大因子
    if (mp[a]>0) return mp[a];
    for(int i=2;i*i<=a;i++){
        if (a%i==0){
            mp[a]=a/i;
            return mp[a];
        }
    }
    return mp[a]=1;
}
int main(){
    cin>>q;
    while(q--){
        cin>>x>>y;
        int cnt=0;//距离
        while(x!=y){//不相等,即没到共同根
            if (x>y){//谁大,就求谁的父节点
                x=f(x);
            }else{
                y=f(y);
            }
            cnt++;//距离增加1
        }
        cout<<cnt<<"\n";
    }
	return 0;
}

### 关于20239月CCF-GESP计算机学会等级考试二级C++ T2题目解答 数字黑洞问题通常涉及对四位数的操作,通过特定算法不断迭代直到达到某个固定值即所谓的“数字黑洞”。对于不使用数组和额外定义函数的要求下解决此问题的方法如下: 为了处理输入的整数值并对其进行操作,可以利用除法与取余运算提取每一位上的数字。具体来说,在不需要借助数组的情况下获取各个位上的数字可以通过连续地将当前值除以10以及求模来完成。 ```cpp #include <iostream> using namespace std; int main() { int n; cin >> n; // 输入一个四位正整数 while (n != 6174 && !(n >= 1000 && n <= 9999)) { // 当不是6174且为有效四位数时循环 if(n<1000){ cout << "Input should be a four-digit number." << endl; break; } int asc = 0, desc = 0; for(int i=0;i<4;++i){ // 构造升序排列的新数字asc 和降序排列的新数字desc int digit = n % 10; asc += pow(10,i)*digit; desc+=pow(10,(3-i))*digit; n /= 10; } n = abs(desc - asc); // 对新构建的一组最大最小组合做差得到新的待处理数 cout<<desc<<"-"<<asc<<"="<<n<<endl; } return 0; } ``` 上述代码展示了如何仅依靠基本控制语句和算术运算符解决问题[^1]。这里的关键在于理解如何分离出每一个单独的位置上所代表的具体数值,并据此创建两个极端情况下的重排版本——一个是按递增顺序形成的较小数`asc`;另一个则是按照递减方式组成的较大数`desc`。之后再计算两者之间的差异作为下一步骤中的原始数据继续执行相同的过程直至满足终止条件为止。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

长春高老师信奥工作室

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

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

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

打赏作者

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

抵扣说明:

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

余额充值