2026萌新联赛第三场-- (郑州轻工业大学)

2026萌新联赛第三场-- (郑州轻工业大学)

前言

真不能闹了,这次比赛做的一塌糊涂啊,看着这个榜单就知道题目不是很难,可是做起来又是一个情况。为什么急躁,为什么死磕,这都是问题啊,由于A题目就是过不了,导致后面有一个基本算是原题都没有做出来,真是没话说了。

全排序那一题本来我看数据才11,那我就用我记得一个公式来做吧,但是谁知道11也会卡TLE,但凡是10就不会卡,真服了,这题不会dfs,看着它过题人数越来越多啊。

本场题目出题人没有给出题范围,那么我就自己来打一下吧

easy H J

easy mid A I G B

mid C E(会板子就只能排在easy mid) F

hard D K

题目链接:(0条未读通知) 河南萌新联赛2026第(三)场:郑州轻工业大学_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ

感兴趣得可以去看一下


H题

H-wnd的魔法背包_河南萌新联赛2026第(三)场:郑州轻工业大学

这个题目可以说很水了,读完题就知道怎么写了。

就是一个向下取整,然后把整数累加,负数从小到大变成正数,注意次数就行了,没什么好说的

AC代码
cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl '\n'
#define int long long
#define pii pair<int,int>
#define fi first
#define se second
#define YES cout<<"YES"<<endl;
#define NO cout<<"NO"<<endl;

const int INF=1e6+5;
void solve()
{
	int n;
	cin>>n;
	vector<int> a;
	int ans=0;
	int shu=n/2;
	for(int i=0;i<n;i++)
	{
		int num;
		cin>>num;
		if(num>0) ans+=num;
		else a.push_back(num);
	}
	sort(a.begin(),a.end());
	int len=a.size();
	shu=min(shu,len);
	for(int i=0;i<shu;i++)
	{
		ans+=(-1*a[i]);
	}
	cout<<ans<<endl;
	// cout<<fixed<<setprecision(x)<<
}
signed main()
{
	IOS;
	int _=1;
	// cin>>_;
	while(_--)
	solve();
	return 0;
}

J题

J-魔法数字_河南萌新联赛2026第(三)场:郑州轻工业大学

思路:这题也很水的题,不过赛时一直在卡TLE,我在想,这数字最多进行三次循环怎么会TLE呢,于是我赛时就改了一下代码浪费了我大量时间,在赛后发现原来最开始的代码有两个地方写错误导致死循环了。不说了,上代码

AC代码
cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl '\n'
#define int long long
#define pii pair<int,int>
#define fi first
#define se second
#define YES cout<<"YES"<<endl;
#define NO cout<<"NO"<<endl;

const int INF=1e6+5;
void solve()
{
	string s;
	cin>>s;
	int num=0;
	if(s.size()==1){
		cout<<0<<' '<<s[0]<<endl;
		return;
	}
	int len=s.size();
	for(int i=0;i<len;i++)
	{
		num+=(s[i]-'0');
	}
	int cnt=1;
	if(num<10){
		cout<<1<<' '<<num<<endl;
		return;
	}
	// cout<<num<<endl;
	int ans=0;
	while(1)
	{
		int shu=num%10;
		ans+=shu;
		num/=10;
        if(num==0) cnt++;
		if(num==0&&ans<10){
			cout<<cnt<<' '<<ans<<endl;
			return;
		}else if(num==0&&ans>=10){
			num=ans;
            ans=0;
		}
	}
	// cout<<fixed<<setprecision(x)<<
}
signed main()
{
	IOS;
	int _=1;
	cin>>_;
	while(_--)
	solve();
	return 0;
}

A题

A-能量任务_河南萌新联赛2026第(三)场:郑州轻工业大学

这个题我说实话,也很简单,你只要把这个贪心思路想出来,把这个排序排出来之后就变得十分好写。

这里有两个方法来写,第一种正常全部数进行排序,我们就根据h从小到大排序,但是如果遇到了d小于0的情况我们得另外判断,因为d小于0相当于如果我们做完这个任务我们的能量不会增加而是会减少,所以这时候我们就看这两个比较的数的d值,怎么排序呢?如果两个数的d都是负数,我们就按照他们hd的和的值,按照从大到小排序,要是一正一负那我们肯定想要增加能量而不是减少,所以按照d从大到小排序。就根据这个排序然后我们再进行二分尝试一个最小能量就行了。

另外一个方法是什么呢?那就是我们按照d的正负来分别排序,正数一个数组,负数一个数组,然后正数按照h从小到大排序,负数那个数组我们还是按照h+d的和从大到小排序,然后这两个数组都排完序了,我们先便利正数数组,然后再遍历负数数组,进行二分尝试,找一个最小的值。

哦,对了,忘记解释二为什么不按照正规排序也可以了,由于我们不想让能量降低,那么干脆就先把增加的能量过完了再进行降低能量的任务,因为就算我这个任务先做了,那么可能到后面这个能量就到不了下一个的门槛,但是由于没有做这个减少能量的任务,我们可以做下一个增加能量的任务。这就方便的多,先找一个能通过所有的正数的最小值,然后看看这个最小值在负数那里面符不符合,不符合我们再在这个最小值的基础上找。

AC代码(法1)
cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl '\n'
#define int long long
#define pii pair<int,int>
#define fi first
#define se second
#define YES cout<<"YES"<<endl;
#define NO cout<<"NO"<<endl;

const int INF=1e6+5;
int ksm(int a, int b, int p) {
	int res = 1;
	while (b) {
		if (b & 1) res = res * a % p;
		a = a * a % p;
		b >>= 1;
	}
	return res;
}
struct node{
	int h,d;
	int id;
};
bool cmp(node a,node b)
{
	if(a.d<0||b.d<0)
    {
        if(a.d==b.d)return a.h>b.h;
        else if(a.d<0&&b.d<0)
        {
            int c=a.h+a.d;
            int d=b.h+b.d;
            return c>d;
        }
        else return a.d>b.d;
    }
    return a.h<b.h;
}
void solve()
{
	int n;
	cin>>n;
	vector<node> a(n);
	for(int i=0;i<n;i++) {
		cin>>a[i].h>>a[i].d;
	}
	sort(a.begin(),a.end(),cmp);
	int l=0,r=LLONG_MAX;
	int ans=-1;
	while(l<=r)
	{
		int mid=(l+r)/2;
		int num=mid;
		bool ok=true;
		for(int i=0;i<n;i++)
		{
			if(num<a[i].h){
				ok=false;
				break;
			}else{
				num+=a[i].d;
			}
		}
		if(!ok) {
			l=mid+1;
		}
		else{
			r=mid-1;
			ans=mid;
		}
	}
	cout<<ans<<endl;
	// cout<<fixed<<setprecision(x)<<
}
signed main()
{
	IOS;
	int _=1;
	// cin>>_;
	while(_--)
	solve();
	return 0;
}
AC代码(法2)
cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl '\n'
#define int long long
#define pii pair<int,int>
#define fi first
#define se second
#define YES cout<<"YES"<<endl;
#define NO cout<<"NO"<<endl;

const int INF=1e6+5;
int n;
vector<pii> a1;
vector<pii> a2;
vector<pii> arr;
bool cmp1(pii a,pii b)
{
	if(a.fi==b.fi) return a.se>b.se;
	return a.fi<b.fi;
}
bool cmp2(pii a,pii b)
{
	return a.fi+a.se>b.fi+b.se;
}
bool check(int x)
{
	for(int i=0;i<n;i++)
	{
		if(x<arr[i].fi){
			return false;
		}else{
			x+=arr[i].se;
		}
	}
	return true;
}
void solve()
{
	cin>>n;
	for(int i=0;i<n;i++) {
		int num1,num2;
		cin>>num1>>num2;
		if(num2>=0){
			a1.push_back({num1,num2});
		}else{
			a2.push_back({num1,num2});
		}
	}
	sort(a1.begin(),a1.end(),cmp1);
	sort(a2.begin(),a2.end(),cmp2);
	int len1=a1.size();
	int len2=a2.size();
	for(int i=0;i<len1;i++) arr.push_back({a1[i].fi,a1[i].se});
	for(int i=0;i<len2;i++) arr.push_back({a2[i].fi,a2[i].se});
	int l=0,r=LLONG_MAX;
	int ans=LLONG_MAX;
	while(l<=r)
	{
		int mid=(l+r)/2;
		if(check(mid)){
			r=mid-1;
			ans=mid;
		}else{
			l=mid+1;
		}
	}
	cout<<ans<<endl;
	// cout<<fixed<<setprecision(x)<<
}
signed main()
{
	IOS;
	int _=1;
	// cin>>_;
	while(_--)
	solve();
	return 0;
}

G题

G-wnd的魔法排序_河南萌新联赛2026第(三)场:郑州轻工业大学

思路:本题是有一个全排列公式的,但是我在赛时是试了的,如果n等于10的话就恰好能过,但是等于11可能就差点,那么如果遇到n很小的时候我们可以用全排列公式next_permutation

那如果用不了公式怎么办呢?那我们就想全排列的底层逻辑啊,那不就是选择一个数然后再选择剩下的数,然后一层一层的选择数字,那不就是dfs递归嘛,可是赛时dfs就是不会写,没办法,赛时只能干着急,只能赛后补了-_- 这个dfs其实是很好写的,就通过一层一层递归定义一个标记数组,表示这个数字被选择了没有,然后我们在选择数字的过程中进行判断数字合不合理,也就是相邻两个数字和得是质数,然后如果途中这个选择就不行我们就直接跳过走下一步,这里就是为什么全排列TLE的原因,因为全排列会把所有的情况列出来再判断,而我们dfs可以在n个数字形成之前就pass一些不可以的数字,节省了一点时间。

然后我们定义一个记录数量的,这个数量等于n我们就把这个数组输出出来然后回退到上一层接着遍历,注意的是我们回退之后这个数字我们得把它重新标记为没用过(也就是回溯)。

AC代码
cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl '\n'
#define int long long
#define pii pair<int,int>
#define fi first
#define se second
#define YES cout<<"YES"<<endl;
#define NO cout<<"NO"<<endl;

const int INF=1e6+5;
int n;
int a[30];
int vis[30]={0};
int ans[30];
bool check(int x)
{
	if(x==2) return true;
	for(int i=2;i<=sqrt(x);i++)
	{
		if(x%i==0) return false;
	}
	return true;
}
void dfs(int step)
{
	if(step==n)
	{
		for(int i=1;i<=n;i++) cout<<ans[i]<<' ';
		cout<<endl;
		return;
	}
	for(int i=1;i<=n;i++)
	{
		if(vis[i]) continue;
		if(step==0||check(ans[step]+i)) ans[step+1]=i;
		else continue;
		vis[i]=1;
		dfs(step+1);
		vis[i]=0;
	}
}
void solve()
{
	cin>>n;
	for(int i=1;i<=n;i++) a[i]=i;
	dfs(0);
	// cout<<fixed<<setprecision(x)<<
}
signed main()
{
	IOS;
	int _=1;
	// cin>>_;
	while(_--)
	solve();
	return 0;
}

I题

I-遗迹核心的临界容差_河南萌新联赛2026第(三)场:郑州轻工业大学

这个题就是一个很简单并且很板子的二分答案题目啊,我们通过二分尝试,然后取最小值就行了。其实没什么好说的,当时开的人少加上自己死磕A题就没看这题,就一个板子二分

AC代码
cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl '\n'
#define int long long
#define pii pair<int,int>
#define fi first
#define se second
#define YES cout<<"YES"<<endl;
#define NO cout<<"NO"<<endl;

const int INF=1e9+5;
int n,k;
vector<int> a;
vector<int> cha;
bool check(int mid)
{
	int cnt=0;
	for(int i=0;i<n-1;i++)
	{
		if(cha[i]>mid) cnt++;
	}
	return cnt<k; 
}
void solve()
{
	cin>>n>>k;
	a.resize(n);
	cha.resize(n);
	for(int i=0;i<n;i++) cin>>a[i];
	for(int i=0;i<n-1;i++) cha[i]=abs(a[i+1]-a[i]);
	int l=0,r=INF;
	int ans=INF;
	while(l<=r)
	{
		int mid=(l+r)/2;
		if(check(mid)){
			r=mid-1;
			ans=mid;
		}else{
			l=mid+1;
		}
	}
	cout<<ans<<endl;
	// cout<<fixed<<setprecision(x)<<
}
signed main()
{
	IOS;
	int _=1;
	// cin>>_;
	while(_--)
	solve();
	return 0;
}

B题

B-三色平衡_河南萌新联赛2026第(三)场:郑州轻工业大学

思路:这个题我们可以通过数学思维,用前缀和加哈希来做

首先题目要求的我们转化一个含义就可以表示为一段区间

cnt0=cnt1=cnt2

那么我们把这个式子转化一下变成cnt0-cnt1=cnt0-cnt2

当然也可以写成cnt0-cnt1=cnt2-cnt1,这些都无所谓,我们只是想要一个式子,那么我们哈希表里面寻访的是前缀我们遇到的cnt0-cnt1,cnt0-cnt2两个差值的最远的一个下标,然后如果后面我们遇到了这个相等的差值,就表示中间的012的个数相等才会出现一样的cnt0-cnt1,cnt0-cnt2,那么我们这时候不更新哈希,只能新长度就行了

AC代码
cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl '\n'
#define int long long
#define pii pair<int,int>
#define fi first
#define se second
#define YES cout<<"YES"<<endl;
#define NO cout<<"NO"<<endl;

const int INF=1e6+5;
map<pii,int> mp;
void solve()
{
	int n;
	cin>>n;
	string s;
	cin>>s;
	int cnt0=0,cnt1=0,cnt2=0;
	int ans=0;
	mp[{0,0}]=0;
	for(int i=0;i<n;i++)
	{
		if(s[i]=='0') cnt0++;
		if(s[i]=='1') cnt1++;
		if(s[i]=='2') cnt2++;
		pii t={cnt0-cnt1,cnt0-cnt2};
		if(mp.count(t)) ans=max(ans,i+1-mp[t]);
		else mp[t]=i+1;
	}
	cout<<ans<<endl;
	// cout<<fixed<<setprecision(x)<<
}
signed main()
{
	IOS;
	int _=1;
	// cin>>_;
	while(_--)
	solve();
	return 0;
}

E题

E-传话_河南萌新联赛2026第(三)场:郑州轻工业大学

思路:这个题其实也不难,就是一个并查集的应用,找所有弱连通分量中节点数的最大值。根据题目的意思来讲,我们可以不考虑方向问题,直接定义一个人当"老大",然后找每个连通分量的长度,我们取最大值就行了。并查集怎么用的话,怎么说呢?感觉这题比较简单吧,我们肯定首先定义自己是自己的老大,然后合并u,v,任意让谁当老大,v当就行,然后只要find函数找两个人的老大,要是不是一个人我们就把他们合并,然后把它的小弟加上就行了,具体看代码就懂了。

AC代码
cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl '\n'
#define int long long
#define pii pair<int,int>
#define fi first
#define se second
#define YES cout<<"YES"<<endl;
#define NO cout<<"NO"<<endl;

const int INF=1e6+5;
int fa[INF];
int sz[INF];
int find(int x)
{
	if(x==fa[x]) return x;
	return fa[x]=find(fa[x]);
}
void unite(int u,int v)
{
	u=find(u);
	v=find(v);
	if(u!=v)
	{
		fa[u]=v;
		sz[v]+=sz[u];
	}
}
void solve()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		fa[i]=i;
		sz[i]=1;
	}
	for(int i=1;i<=n;i++){
		int p;
		cin>>p;
		unite(i,p);
	}
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		if(find(i)==i) ans=max(ans,sz[i]);
	}
	cout<<ans<<endl;
	// cout<<fixed<<setprecision(x)<<
}
signed main()
{
	IOS;
	int _=1;
	cin>>_;
	while(_--)
	solve();
	return 0;
}

C题

C-余数清理_河南萌新联赛2026第(三)场:郑州轻工业大学

这个题涉及到"同余定理"的数论知识,如果理解了这个知识点我们就很好写了,这个结论首先给出,下面会有解释和推论。

就是

p ( l − 1 ) = ( p r − t a r g e t + m ) m o d m p(l-1)=(pr-target+m)modm p(l−1)=(pr−target+m)modm

其中呢,我们的p数组是前缀和对m取余的结果,这个target就等于pn,然后我们遍历数组,这个指针指的是pr,那么这时候的pl-1就可以表示出来了,也是我们需要查找的值,在我们i左边遍历的过程中看看有没有出现过 (pr - target + m) mod m

出现过我们就计算这个长度并且更新这个出现的位置为右边的,如果没有找到就只更新这个出现位置。

这个查找过程我们需要用到哈希来实现。
下面我们讲解一下这个上面推论公式是如何得来的。

如图


如果这个结论理解了,那么我们再回到思路来看看是否理解如何做。

AC代码
cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl '\n'
#define int long long
#define pii pair<int,int>
#define fi first
#define se second
#define YES cout<<"YES"<<endl;
#define NO cout<<"NO"<<endl;

const int INF=1e6+5;
void solve()
{
	int n,m;
	cin>>n>>m;
	vector<int> a(n+1);
	vector<int> p(n+1);
	for(int i=1;i<=n;i++) cin>>a[i];
	p[1]=a[1]%m;
	for(int i=2;i<=n;i++) p[i]=(p[i-1]+a[i])%m;
	vector<int> vis(m,-1);
	int ans=INF;
	int target=p[n];
	vis[0]=0;
	for(int i=1;i<=n;i++)
	{
		int shu=(p[i]-target+m)%m;
		if(vis[shu]!=-1&&i-vis[shu]<n) ans=min(ans,i-vis[shu]);
		vis[p[i]]=i;
	}
	if(ans>n) cout<<-1<<endl;
	else cout<<n-ans<<endl;
	// cout<<fixed<<setprecision(x)<<
}
signed main()
{
	IOS;
	int _=1;
	// cin>>_;
	while(_--)
	solve();
	return 0;
}

总结

这场比赛只能说一言难尽,最后吟诗一首歌颂我逝去的比赛

鏖罢方知梦未安,

功亏一瞬意难宽。

一腔愤懑摧胸臆,

半卷烽烟染泪澜。

莫叹今朝锋铩羽,

当磨来日剑重弹。

埋愁且蓄凌云志,

再赴征场破万难。

相关推荐
梓䈑1 小时前
【用 Vibe Coding 实现的 C++17 在线判题系统】前端开发 + Web 自动化测试
前端·c++·ai编程
冻柠檬飞冰走茶1 小时前
PTA基础编程题目集 7-8超速判断(C++语言实现)
开发语言·数据结构·c++·算法
玖玥拾2 小时前
LeetCode 88 合并两个有序数组
算法·leetcode
TunerT_TQ2 小时前
Valhalla 静态工程审阅 #018|MMCV 源码证据驱动评测【大厂开源基础设施特辑】
c++·开源·mfc·#计算机视觉·#商汤科技·#openmmlab·#静态源码审计
数据皮皮侠AI2 小时前
上市公司数字供应链金融指数(2010-2024)
大数据·人工智能·算法
2501_942389552 小时前
Epoch AI旗下FrontierMath的负责人Elliot Glazer
数据结构·决策树·动态规划·散列表
山峰哥2 小时前
数据库工程与SQL调优:从慢查询到秒级响应的实战之路
java·开发语言·数据库·sql·深度优先·启发式算法
小程故事多_802 小时前
用GRPO算法重塑多智能体系统,从原理落地到复杂任务规划实战
人工智能·算法
别动我齐刘海3 小时前
Day6 unitree_G1人形机器人GMR—— MotionInput
c语言·c++·人工智能·学习·机器学习·机器人·github