2025年12月GESP(C++五级): 相等序列

2025年12月GESP(C++五级): 相等序列

题目描述

小 A 有一个包含 N N N 个正整数的序列 A = { A 1 , A 2 , ... , A N } A=\{A_1,A_2,\ldots,A_N\} A={A1,A2,...,AN}。小 A 每次可以花费 1 1 1 个金币执行以下任意一种操作:

  • 选择序列中一个正整数 A i A_i Ai( 1 ≤ i ≤ N 1\le i\le N 1≤i≤N),将 A i A_i Ai 变为 A i × P A_i\times P Ai×P, P P P 为任意质数;
  • 选择序列中一个正整数 A i A_i Ai( 1 ≤ i ≤ N 1\le i\le N 1≤i≤N),将 A i A_i Ai 变为 A i P \frac{A_i}{P} PAi, P P P 为任意质数,要求 A i A_i Ai 是 P P P 的倍数。

小 A 想请你帮他计算出令序列中所有整数都相同,最少需要花费多少金币。

输入格式

第一行一个正整数 N N N,含义如题面所示。

第二行包含 N N N 个正整数 A 1 , A 2 , ... , A N A_1,A_2,\ldots,A_N A1,A2,...,AN,代表序列 A A A。

输出格式

输出一行,代表最少需要花费的金币数量。

输入输出样例 1
输入 1
复制代码
5
10 6 35 105 42
输出 1
复制代码
8
说明/提示

对于 60 % 60\% 60% 的测试点,保证 1 ≤ N , A i ≤ 100 1\le N,A_i\le 100 1≤N,Ai≤100。

对于所有测试点,保证 1 ≤ N , A i ≤ 10 5 1\le N,A_i\le 10^5 1≤N,Ai≤105。

思路分析

这个问题要求通过乘以质数或除以质数(当可整除时)的操作,使得序列中所有数相等,求最小操作次数。

核心思路
  1. 质因数分解视角:操作的本质是改变每个数的质因数指数:

    • 乘以质数 P P P:增加该质数指数的值(+1)
    • 除以质数 P P P:减少该质数指数的值(-1)
  2. 独立处理质因数:每个质因数的操作是独立的。最终所有数相等意味着每个质因数的指数在所有数中都相同。

  3. 问题转化 :对于每个质数 p p p,我们有一个长度为 N N N 的数组,表示每个数中 p p p 的指数。我们需要通过增减操作(增减1)使所有指数相等,求最小总操作次数。

  4. 中位数最优性

    • 对于一组数,使它们相等的最优目标值是中位数
    • 证明:如果将目标值从 k k k 变为 k + 1 k+1 k+1,那么所有 ≤ k ≤k ≤k 的数需要多操作1次,所有 > k >k >k 的数可以少操作1次,当小于等于目标值的个数超过一半时,继续增加目标值会减少总操作次数,反之亦然。
  5. 处理未出现的数 :对于某个质数 p p p,有些数可能没有这个质因数(指数为0),这些数也需要考虑在内。

算法步骤
  1. 对每个数进行质因数分解,记录每个质数的指数
  2. 对于每个质数 p p p:
    • 统计 p p p 在多少个数的质因数分解中出现(记作 c c c)
    • 未出现的数有 n − c n-c n−c 个,这些数的指数为0
    • 找到所有出现 p p p 的数的指数中位数
    • 计算将所有数的 p p p 指数调整到中位数的操作次数
  3. 累加所有质数的操作次数

代码实现

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
typedef long long ll;
ll n;
vector<ll> v[N]; // v[i]存储质数i在所有数中的指数列表

int main(){
    cin>>n;
    
    // 1. 质因数分解,记录每个质数的指数
    for(int i=1;i<=n;i++){
        ll x;
        cin>>x;
        // 分解质因数
        for(int j=2;j<=sqrt(x);j++){
            ll cnt=0;
            while(x%j==0){
                cnt++;
                x/=j;
            }
            if(cnt>0) v[j].push_back(cnt); // 记录质数j的指数
        }
        // 处理剩余的质因数
        if(x!=1) v[x].push_back(1);    
    }
    
    ll ans=0;
    
    // 2. 对每个质数计算最小操作次数
    for(int i=2;i<=100000;i++){
        ll c=v[i].size(); // 有多少个数包含质数i
        ll zeroc=n-c; // 不包含质数i的数字个数(指数为0)
        
        // 如果没有任何数包含质数i,跳过
        if(c==0) continue;
        
        // 对指数进行排序,便于找中位数
        sort(v[i].begin(),v[i].end());
        
        // 计算中位数的位置
        ll mid=(n-1)/2;
        ll zws; // 中位数
        
        // 确定中位数
        if(mid<zeroc){
            // 中位数落在0的部分
            zws=0;
        }else{
            // 中位数落在非零指数部分
            zws=v[i][mid-zeroc];
        }
        
        // 3. 计算操作次数
        // 对于指数为0的数,每个需要操作zws次(增加zws次)
        ll opt=zeroc*zws;
        // 对于有指数的数,每个需要操作|指数-中位数|次
        for(int j=0;j<v[i].size();j++){
            opt+=abs(v[i][j]-zws);
        }
        
        // 4. 累加到总答案
        ans+=opt;
    }
    cout<<ans;
    return 0;
}

功能分析

时间复杂度
  • 质因数分解 :每个数 A i A_i Ai 分解质因数需要 O ( A i ) O(\sqrt{A_i}) O(Ai ),最坏情况下 A i = 10 5 A_i=10^5 Ai=105, A i ≈ 316 \sqrt{A_i}≈316 Ai ≈316,总复杂度 O ( N max ⁡ A i ) ≈ 3 × 10 7 O(N\sqrt{\max A_i})≈3×10^7 O(NmaxAi )≈3×107
  • 排序部分 :每个质数对应的指数列表排序,总指数个数为所有数的质因数总个数,约为 O ( N log ⁡ max ⁡ A i ) O(N\log \max A_i) O(NlogmaxAi)
  • 总体复杂度可以接受
空间复杂度
  • 使用 vector<ll> v[N] 存储每个质数的指数列表
  • 每个数最多有 O ( log ⁡ A i ) O(\log A_i) O(logAi) 个质因数,总空间 O ( N log ⁡ max ⁡ A i ) O(N\log \max A_i) O(NlogmaxAi)
正确性验证

以样例为例:

复制代码
输入:5
      10 6 35 105 42

质因数分解:

  • 2: 在10(1), 6(1), 42(1)中出现,指数列表[1,1,1],有2个0
    • 中位数是1,操作次数 = 2×1 + (|1-1|×3) = 2
  • 3: 在6(1), 105(1), 42(1)中出现,指数列表[1,1,1],有2个0 → 2次操作
  • 5: 在10(1), 35(1), 105(1)中出现,指数列表[1,1,1],有2个0 → 2次操作
  • 7: 在35(1), 105(1), 42(1)中出现,指数列表[1,1,1],有2个0 → 2次操作
    总操作次数 = 2+2+2+2 = 8,与样例输出一致。
关键点
  1. 中位数选择:选择中位数作为目标值能最小化绝对差之和
  2. 零指数处理:未出现的数(指数为0)必须考虑在内
  3. 质数范围:只需要处理实际出现的质数,不需要遍历所有1e5以内的质数
  4. 独立处理:不同质因数的操作相互独立,可以分别计算后求和

各种学习资料,助力大家一站式学习和提升!!!

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	cout<<"##########  一站式掌握信奥赛知识!  ##########";
	cout<<"#############  冲刺信奥赛拿奖!  #############";
	cout<<"######  课程购买后永久学习,不受限制!   ######";
	return 0;
}
  • 一、CSP信奥赛C++通关学习视频课:
    • C++语法基础
    • C++语法进阶
    • C++算法
    • C++数据结构
    • CSP信奥赛数学
    • CSP信奥赛STL
  • 二、CSP信奥赛C++竞赛拿奖视频课:
    • 信奥赛csp-j初赛高频考点解析
    • CSP信奥赛C++复赛集训课(12大高频考点专题集训)
  • 三、考级、竞赛刷题题单及题解:
    • GESP C++考级真题题解
    • CSP信奥赛C++初赛及复赛高频考点真题解析
    • CSP信奥赛C++一等奖通关刷题题单及题解

详细内容:

1、csp/信奥赛C++,完整信奥赛系列课程(永久学习):

https://edu.csdn.net/lecturer/7901 点击跳转


2、CSP信奥赛C++竞赛拿奖视频课:

https://edu.csdn.net/course/detail/40437 点击跳转

3、csp信奥赛冲刺一等奖有效刷题题解:

CSP信奥赛C++初赛及复赛高频考点真题解析(持续更新):https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转

  • 2025 csp-j 复赛真题及答案解析(最新更新)
  • 2025 csp-x(山东) 复赛真题及答案解析(最新更新)
  • 2025 csp-x(河南) 复赛真题及答案解析(最新更新)
  • 2025 csp-x(辽宁) 复赛真题及答案解析(最新更新)
  • 2025 csp-x(江西) 复赛真题及答案解析(最新更新)
  • 2025 csp-x(广西) 复赛真题及答案解析(最新更新)
  • 2020 ~ 2024 csp 复赛真题题单及题解
  • 2019 ~ 2022 csp-j 初赛高频考点真题分类解析
  • 2021 ~ 2024 csp-s 初赛高频考点解析
  • 2023 ~ 2024 csp-x (山东)初赛真题及答案解析
  • 2024 csp-j 初赛真题及答案解析
  • 2025 csp-j 初赛真题及答案解析(最新更新)
  • 2025 csp-s 初赛真题及答案解析(最新更新)
  • 2025 csp-x (山东)初赛真题及答案解析(最新更新)
  • 2025 csp-x (江西)初赛真题及答案解析(最新更新)
  • 2025 csp-x (辽宁)初赛真题及答案解析(最新更新)

CSP信奥赛C++一等奖通关刷题题单及题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12673810.html 点击跳转

  • 129 道刷题练习和详细题解,涉及:模拟算法、数学思维、二分算法、 前缀和、差分、深搜、广搜、DP专题、 树和图

4、GESP C++考级真题题解:

GESP(C++ 一级+二级+三级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12858102.html 点击跳转

GESP(C++ 四级+五级+六级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12869848.html 点击跳转

· 文末祝福 ·

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	cout<<"跟着王老师一起学习信奥赛C++";
	cout<<"    成就更好的自己!       ";
	cout<<"  csp信奥赛一等奖属于你!   ";
	return 0;
}
相关推荐
TDengine (老段)11 小时前
TDengine C/C++ 连接器入门指南
大数据·c语言·数据库·c++·物联网·时序数据库·tdengine
自然语11 小时前
人工智能之数字生命-特征类升级20260106
人工智能·算法
菜鸟233号11 小时前
力扣343 整数拆分 java实现
java·数据结构·算法·leetcode
赫凯11 小时前
【强化学习】第五章 时序差分算法
算法
vyuvyucd11 小时前
C++ vector容器完全指南
c++
liulilittle11 小时前
XDP VNP虚拟以太网关(章节:三)
网络·c++·网络协议·信息与通信·通信·xdp
leiming611 小时前
c++ find_if 算法
开发语言·c++·算法
yuanmenghao11 小时前
自动驾驶中间件iceoryx - 内存与 Chunk 管理(三)
数据结构·c++·算法·链表·中间件·自动驾驶
_OP_CHEN12 小时前
【算法基础篇】(四十三)数论之费马小定理深度解析:从同余性质到乘法逆元
c++·算法·蓝桥杯·数论·acm/icpc
水月wwww12 小时前
【算法设计】分支限界法
算法·分支限界法