河南萌新联赛2025第(四)场【补题】

目录

A-完美序列

题目链接

解题思路

所谓完美序列,就是让我们找给定的序列a中,选任意元素任意排列顺序,能组成最长的一个满足

的序列的长度。那么我们可以用哈希表mp记录每个数字的个数,然后遍历可能的和的值2~10000,第二层循环从1 ~i/2,为了缩短时间同时防止重复记录,然后再令y=i-j,看满足这个条件的数有多少个,如果他的值和j相等,组合对数就加mp[j]/2,否则就取二者个数的最小值,最后更新一下最大值ans。输出即可。

AC代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define int long long
#define PII pair<int,int>
#define fi first
#define se second
#define endl '\n'
const int N=2e5+5;
const int inf=5000;
int n,num,mp[inf+10];
void solve()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	cin>>num,mp[num]++;
	int ans=0;
	for(int i=2;i<=10000;i++)
	{
		int res=0;
		for(int j=1;j<=i/2;j++)
		{
			int x=i-j;
			if(x>inf)continue;
			if(x==j)
			res+=mp[x]/2;
			else
			res+=min(mp[x],mp[j]);
		}
		ans=max(res,ans);
	}
	cout<<ans*2;	
}
signed main()
{
	IOS;
	int _=1;
//	cin>>_;
	while(_--)
	solve();
	return 0;
}

C-合并石子

解题思路

这道题我是分别记录位置i的左边所有数到达它需要的步数和右边所有数需要到达他的总步数,最后再将二者相加就是所有石子需要到达他的总步数。通过前缀和记录每个位置需要移动的石子个数,(数字+k-1)/k是向上取整的意思,再将每个位置的步数累加。然后遍历筛选一个最小的总和,ans初始值不能赋INT_MAX,不然会wa一半。。。因为题目中数字较大,所以初值赋1e18.

AC代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define int long long
#define PII pair<int,int>
#define fi first
#define se second
#define endl '\n'
const int N=1e6+6;
int n,k,a[N],b[N],c[N],s1[N],s2[N],l[N],r[N];
void solve()
{
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	cin>>a[i];
	for(int i=1;i<=n;i++)
	l[i]=l[i-1]+a[i];
	for(int i=n;i>=1;i--)
	r[i]=r[i+1]+a[i];
	for(int i=1;i<=n;i++)
    s1[i]=s1[i-1]+(l[i]+k-1)/k; 
	for(int j=n;j>=1;j--)
	s2[j]=s2[j+1]+(r[j]+k-1)/k;
	int ans=1e18;
	for(int i=1;i<=n;i++)
	ans=min(ans,s1[i-1]+s2[i+1]);
	cout<<ans;
}
signed main()
{
	IOS;
	int _=1;
//	cin>>_;
	while(_--)
	solve();
	return 0;
}

G-封闭运算

题目链接

解题思路

将原有的值都标记,数据范围很小,开双层循环遍历,如果二者异或值在原数组中不存在就输出"NO"如果全都存在就输出"YES".

AC代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define int long long
#define PII pair<int,int>
#define fi first
#define se second
#define endl '\n'
const int N=106;
int n,a[N];
map<int,int>mp;
void solve()
{
	cin>>n;
	int f=1;
	for(int i=1;i<=n;i++)
	cin>>a[i],mp[a[i]]++;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			int x=a[i]|a[j];
			if(mp[x]==0)
			{
				f=0;
				break;
			}
		}
		if(!f)
		break;
	}
	if(f)
	cout<<"YES";
	else
	cout<<"NO";
}
signed main()
{
	IOS;
	int _=1;
//	cin>>_;
	while(_--)
	solve();
	return 0;
}

J-故障机器人的完美牌组

题目链接

解题思路

简单的规律题,不过我错了很多发,第一看错题了,第二考虑少了。

首先如果是1,特判直接输出。

否则就从2~n找到最大值mx和最大值所在的位置j,然后看这个最大值是不是等于0,如果是,就不做处理,因为处理了不仅没有数变大而且长度会变小字典序就变小了。如果不是0,就将j标记,a[1]=a[1]+a[j],输出n-1,然后输出剩下的数,便利到j时不输出,因为已经用掉了。

AC代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define int long long
#define PII pair<int,int>
#define fi first
#define se second
#define endl '\n'
const int N=1e6;
int n,a[N],mx=-1e10,j;
unordered_map<int,int>b;
void solve()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	cin>>a[i],b[a[i]]++;
	if(n==1)
	{
		cout<<n<<endl;
		cout<<a[1]<<endl;
		return ;
	}
	for(int i=2;i<=n;i++)
	{
		if(a[i]>=mx)
		{
			mx=a[i];
			j=i;
		}
	}
	if(mx!=0)
	{
	cout<<n-1<<endl;
	cout<<a[1]+mx<<" "; 
	for(int i=2;i<=n;i++)
	{
		if(i!=j)
		cout<<a[i]<<" ";
	}	
	}
	else
	{
		cout<<n<<endl;
		for(int i=1;i<=n;i++)
		cout<<a[i]<<" ";
	}
		
}
signed main()
{
	IOS;
	int _=1;
//	cin>>_;
	while(_--)
	solve();
	return 0;
}

L-故障机器人的完美遗物

题目链接

解题思路

这道题的核心是判断一个数是否为"完美遗物",并计算所有完美遗物的价值之和 。完美遗物的定义是:该数的因数个数是质数且不等于 2。首先筛出可以开平方的数,这样它的因数一定是奇数个,就有可能是质数。

1. 数学原理(题解核心)

要让 ( d(n) ) 是质数且 ≠ 2,需满足:

  • 因数个数的乘积结果是质数 → 乘积中只能有一个因子(否则质数相乘会得到合数)。
  • 因此,( n ) 的素因数分解形式必须是 ( n = a^{b-1} ) (其中 ( a ) 是素数,( b ) 是质数且 ( b \neq 2 ) )。此时:

    d(n) = (b-1 + 1) = b

    ( b ) 是质数且 ≠ 2,满足"完美遗物"条件。

2. 实现思路

(1)预处理素数(prime 函数)

埃氏筛预处理出一定范围(如 ( 10^6 ) )内的素数,后续用于快速分解因数。

(2)因数个数计算(con 函数)

对输入的数 ( x ),先判断是否为平方数(因为完美遗物的形式是 ( a^{b-1} ),等价于平方数的变形)。若为平方数,对其平方根 ( \text{sqrt}(x) ) 做素因数分解,计算因数个数:

  • 分解平方根的素因数,得到各素因子的指数 ( d )。
  • 因数个数公式变为
    (因为原数是平方根的平方,指数翻倍)。

(3)筛选完美遗物(solve 函数)

遍历所有遗物值:

  • 先判断是否为平方数(否则不可能满足 ( n = a^{b-1} ) 形式)。
  • 对平方根分解,计算因数个数 ( f )。
  • 检查 ( f ) 是否是质数且 ≠ 2,若是则累加价值。

(1)埃氏筛预处理素数

cpp 复制代码
const int N = 1e6 + 5000;
int a[N], b[N], q, k = 0; 
void prime() {
    a[1] = 1; // 1 不是素数
    for (int i = 2; i < N; i++) {
        if (a[i] == 0) b[++k] = i; // 记录素数
        for (int j = 1; j <= k && i * b[j] < N; j++) {
            a[i * b[j]] = 1; // 标记非素数
            if (i % b[j] == 0) break; // 保证每个合数只被最小素因子筛掉
        }
    }
}
  • a[] 标记是否为素数,b[] 存储素数列表。
  • 埃氏筛的核心是"用已知素数标记其倍数",保证效率。

(2)因数个数计算(con 函数)

cpp 复制代码
int con(int x) {
    if (x == 1) return 1; 
    int c = 1; 
    for (int i = 1; i <= k; i++) { 
        int p = b[i]; 
        if (p * p > x) break; // 超过平方根,无需继续
        if (x % p == 0) { 
            int d = 0; 
            while (x % p == 0) { // 分解出所有 p 的因子
                x /= p; 
                d++; 
            }
            c *= (d * 2 + 1); // 原数是平方数,指数翻倍后计算因数个数
        }
    }
    if (x > 1) c *= 3; // 剩余大素数因子(指数为1,翻倍后指数为2,d=1 → 2*1+1=3)
    return c; 
}

(3)主函数(solve 函数)

cpp 复制代码
void solve() {
    int n, sum = 0; 
    prime(); // 预处理素数
    cin >> n; 
    vector<int> e(n + 1); 
    for (int i = 1; i <= n; i++) cin >> e[i]; 
    for (int i = 1; i <= n; i++) { 
        int x = e[i]; 
        int ii = sqrt(x); 
        if (ii * ii != x) continue; // 不是平方数,直接跳过
        int f = con(ii); // 计算平方根的因数个数(即原数的因数个数)
        if (a[f] == 0 && f > 2) { // 因数个数是素数且 ≠2
            sum += x; 
        }
    }
    cout << sum << endl; 
}
  • 先筛出平方数(非平方数不可能满足完美遗物条件)。
  • 对平方数,通过 con 计算因数个数,再判断是否为"质数且 ≠2",若是则累加价值。

AC代码

cpp 复制代码
#include<bits/stdc++.h>
#define int long long
using namespace std;

const int N = 1e6 + 5000;
int a[N], b[N], k = 0; // a数组标记是否为素数,b数组存储素数

// 埃氏筛法预处理素数
void prime() {
    a[1] = 1; // 1不是素数
    for (int i = 2; i < N; i++) {
        if (a[i] == 0) {
            b[++k] = i; // 记录素数
        }
        // 标记非素数
        for (int j = 1; j <= k && i * b[j] < N; j++) {
            a[i * b[j]] = 1;
            if (i % b[j] == 0) break; // 优化,避免重复标记
        }
    }
}

// 计算x的因数个数相关值(针对平方数的平方根)
int con(int x) {
    if (x == 1) return 1;
    int c = 1;
    for (int i = 1; i <= k; i++) {
        int p = b[i];
        if (p * p > x) break; // 超过平方根,无需继续
        if (x % p == 0) {
            int d = 0;
            // 分解出所有p的因子
            while (x % p == 0) {
                x /= p;
                d++;
            }
            c *= (d * 2 + 1); // 计算因数个数
        }
    }
    if (x > 1) c *= 3; // 处理剩余的大素数因子
    return c;
}

signed main() {
    prime(); // 预处理素数
    int n, sum = 0;
    cin >> n;
    vector<int> e(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> e[i];
    }
    
    for (int i = 1; i <= n; i++) {
        int x = e[i];
        int ii = sqrt(x);
        // 先判断是否为平方数(非平方数不可能是完美遗物)
        if (ii * ii != x) continue;
        // 计算因数个数
        int f = con(ii);
        // 判断因数个数是否为素数且不等于2
        if (a[f] == 0 && f > 2) {
            sum += x;
        }
    }
    
    cout << sum << endl;
    return 0;
}
相关推荐
weixin_3077791342 分钟前
Redis Windows迁移方案与测试
c++·windows·redis·算法·系统架构
仪器科学与传感技术博士2 小时前
python:讲懂决策树,为理解随机森林算法做准备,以示例带学习,通俗易懂,容易理解和掌握
python·算法·决策树
zm3 小时前
bool 类型转换运算符重载
c++
小指纹3 小时前
cf--思维训练
c++·算法·macos·ios·objective-c·cocoa
菜鸟555553 小时前
河南萌新联赛2025第四场-河南大学
c++·算法·思维·河南萌新联赛
源远流长jerry3 小时前
C++、STL面试题总结(二)
jvm·c++
小坏坏的大世界3 小时前
C++中多线程和互斥锁的基本使用
开发语言·c++
Y4090013 小时前
List、ArrayList 与顺序表
数据结构·笔记·list
F_D_Z3 小时前
【感知机】感知机(perceptron)模型与几何解释
学习·算法·支持向量机