2026河南萌新联赛第四场--南阳理工学院

2026河南萌新联赛第四场--南阳理工学院

前言

这场也是颇为丰富的一场比赛啊,很多简单板子题,数学题也很多。特别是最后一题,纯高数问题!!!

其他的有一个简单的01背包,基本还是板子题,知识有一点变种,然后还有变种bfs,其实能写的那几道都还行,难度都不大,其他的就比较考察算法了。
我得注重dp了,但是这玩意太烧脑了,赛时压根想不起来,一个简单的01背包我在赛事也是乱写一番啊。


只能说这场难度是有的,能写的大概是CDGHJLM(对于我现在来说)IIII I也能写

不是这个I也太那个了吧,好吧,这个I是我眼拙,它榜歪了!

我这里的H没有补,以后学精透了我再来补充

好吧,这个H题看着吓人,实际上这个dp也不是很难吧,特此补题!


M题

M-噢耶,奶奶的龙!!!_河南萌新联赛2026第(四)场:南阳理工学院

纯高数问题,最后一项答案是0,所以答案0

php 复制代码
0

L题

L-A × B_河南萌新联赛2026第(四)场:南阳理工学院

高精度乘法模板

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 s1;
	string s2;
	cin>>s1>>s2;
    int n=s1.size(),m=s2.size();
    vector<int> ans(n+m,0);
    reverse(s1.begin(),s1.end());
    reverse(s2.begin(),s2.end());
    for(int i=0;i<n;i++) {
        for (int j=0;j<m;j++) {
            ans[i+j]+=(s1[i]-'0')*(s2[j]-'0');
        }
    }
    for(int i=0;i<n+m-1;i++) {
        ans[i+1]+=ans[i]/10;
        ans[i]%=10;
    }
    while(ans.size()>1&&ans.back()==0) ans.pop_back();
    for(int i=ans.size()-1;i>=0;i--){
    	cout<<ans[i];
    }
    cout<<endl;
	// cout<<fixed<<setprecision(x)<<
}
signed main()
{
	IOS;
	int _=1;
	// cin>>_;
	while(_--)
	solve();
	return 0;
}

G题

G-你逃不过我你信不信_河南萌新联赛2026第(四)场:南阳理工学院

思路题一道啊,看到这题第一感觉就是打表,果不其然,规律出来了,在n等于20以内没啥规律,我们可以用代码输出,在20以后答案都是0313

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;
}
void solve()
{
	int n;
	cin>>n;
	int shu=1;
	int ans=1;
	if(n<=20){
		for(int i=2;i<=n;i++) 
		{
			if(shu>10000) shu=shu%10000;
			ans*=i;
			if(ans>10000) ans=ans%10000;
			shu+=ans;
		}
		int num=shu%10000;
		int wei=0;
		int num1=num;
		while(num1)
		{
			num1/=10;
			wei++;
		}
		for(int i=0;i<4-wei;i++) cout<<0; 
		cout<<num<<endl;
	}else{
		cout<<"0313"<<endl;
	}
	// cout<<fixed<<setprecision(x)<<
}
signed main()
{
	IOS;
	int _=1;
// 	cin>>_;
	while(_--)
	solve();
	return 0;
}

J题

J-小苯的星轨_河南萌新联赛2026第(四)场:南阳理工学院

这题不还是一个数学题嘛,问你两个点构成的线过不过原点,那我们只需要存斜率比较斜率就行了啊。但是值得注意的是我们的斜率得用数字来存,并且得存的是比值的约分之后的结果。赛时我一直在算double,发现有误差一直过不了,所以这里我们可以改成pii存分子分母,存之前用gcd先约分一下就行。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl '\n'
#define pii pair<int,int>
#define fi first
#define se second
int zuhe(int x)
{
	return x*(x-1)/2;
}
void solve()
{
	int n;
	cin >> n;
	vector<int>x(n+1,0);
	vector<int>y(n+1,0);
	map<pii,int>mp;
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		cin >> x[i] >> y[i];
		if(x[i]==0&&y[i]==0)
		{
			ans+=n-1;
		}
		else
		{
			int g=__gcd(x[i],y[i]);
			mp[{x[i]/g,y[i]/g}]++;
		}
	}
	for(auto &x:mp)
	{
		ans+=zuhe(x.se);
	}
	cout << ans << endl;
}

signed main()
{
	IOS; 
	int T = 1;
	cin >> T;
	while(T --) solve();
	return 0;
}

D题

D-小圆爱玩龙龙(Easy)_河南萌新联赛2026第(四)场:南阳理工学院

经典的01背包问题,由于只能选择一次,所以我们肯定循环是倒着算的

状态转移方程:

cpp 复制代码
dp[i]=max(dp[i],dp[j-X]+Y);

那么我们肯定面临的是选与不选,还有一个免费的,那么我们就再遍历一层循环表示第几个是免费的,然后我们的dp到达这里就跳过,剩下就是经典的01背包模板,第二层循环倒序进行遍历

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;
}
void solve()
{
	int n,W;
	cin>>n>>W;
	vector<int> w(n);
	vector<int> v(n);
	for(int i=0;i<n;i++) cin>>w[i]>>v[i];
	int ans=0;
	for(int f=0;f<n;f++)
	{
		vector<int> dp(W+1,0);
		for(int i=0;i<n;i++)
		{
			if(i==f) continue;
			for(int j=W;j>=w[i];j--)
			{
				dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
			}
		}
		ans=max(ans,dp[W]+v[f]);
	}
	cout<<ans<<endl;
	// cout<<fixed<<setprecision(x)<<
}
signed main()
{
	IOS;
	int _=1;
	// cin>>_;
	while(_--)
	solve();
	return 0;
}

C题

C-重返首发地 (Return to the Origin)_河南萌新联赛2026第(四)场:南阳理工学院

这题是一个搜索问题,我们可以观察到,题目让我们找的是每一个点找到一个P的最近路径,而这题的P是不止一个的,所以正常遍历bfs是肯定不行的,那么我们可以反过来想,我们想要每一个同学都找到P,那么我们可以反过来用P来找其他人的最小路径

那么由于是多个P,所以我们从所有的P一起除法,每一个点谁先到它就是最小的路径。而题目还有一个花费问题,这也是我们走路径关键,有0走0,#不能走,1实在没办法就走,然后如果我们走了一个权值是0的路径,并且这个路径是比之前更加短的那么它的下一个不经肯定是还没走,那么我们肯定是想要走更短的,所以这时候我们想要"插队",就得放到队头。所以这时候我们需要一个双端队列来实现。

详细看代码

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;
const int dx[]={0,0,1,-1};
const int dy[]={1,-1,0,0};
void solve()
{
	int n,m;
	cin>>n>>m;
	vector<string> s(n);
	for(int i=0;i<n;i++) cin>>s[i];
	vector<vector<int>> dist(n,vector<int>(m,INF));//路径初始化为INF
	vector<vector<bool>> vis(n,vector<bool>(m,false));//标记路径
	deque<pii> dq;
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<m;j++)
		{
			if(s[i][j]=='P'){
				dist[i][j]=0;//P点我们的路径肯定是0
				dq.push_back({i,j});
			}
		}
	}
	while(!dq.empty()){
		auto [x,y]=dq.front();
		dq.pop_front();
		if(vis[x][y]) continue;//走过跳过
		vis[x][y]=true;
		
		int w=((s[x][y]=='1')?1:0);
		for(int i=0;i<4;i++)
		{
			int nx=x+dx[i];
			int ny=y+dy[i];
			
			if(nx<0||nx>=n||ny<0||ny>=m) continue;
			if(s[nx][ny]=='#') continue;
			
			if(dist[nx][ny]>dist[x][y]+w){
				dist[nx][ny]=dist[x][y]+w;
				if(w==0) dq.push_front({nx,ny});
				else dq.push_back({nx,ny});
			}
		}
	}
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<m;j++)
		{
			if(dist[i][j]==INF) cout<<-1<<' ';
			else cout<<dist[i][j]<<' ';
		}
		cout<<endl;
	}
	// cout<<fixed<<setprecision(x)<<
}
signed main()
{
	IOS;
	int _=1;
	cin>>_;
	while(_--)
	solve();
	return 0;
}

I题

I-小苯的括号高度_河南萌新联赛2026第(四)场:南阳理工学院

恕我眼拙,这题不涉及任何算法思想,是一个纯纯的数学逻辑加贪心思想的题目,特来补题
首先读完题目我们知道啊,这个k肯定是在<n或者>n*n的时候是不成立的,这个是毋庸置疑的

那么我们通过一顿分析,发现这个(n-k)这个数对2取余,如果是1,那还是不可能,得输出-1。具体推论看下图

既然这个推论出来了,那么我们就可以判断出来三条特判

1: k < n 输出 -1

2:k > n×n 输出 -1

3:(k-n)%2==1 输出 -1

那么剩下就只剩构造了

那么我们的构造又有什么方法呢?

首先我们知道并排是只有n的贡献,那么还差n-k个贡献,而这个贡献需要我们进行嵌套才能实现,那么怎么嵌套呢?我们可以考虑到,遍历到后面的()无非只有两种选择

1:嵌套前面的所有

2:和前面的并列
那么我们考虑到,如果嵌套前面的,那么我们的额外贡献加多少呢?首先我们知道这个括号对是第i个,那么前面已经有i-1个括号对了,由于我们前面所分析的,如果这个括号嵌套前面的,我们可以,哦,抱歉刚发现前面好像并没有分析,那么我们现在分析一下啊:

此时有两种操作:

  1. 直接放在末尾(并列)
    新串 = 旧串 + ()
    这对新括号对总高度贡献是 1(就是它自己的基础贡献),额外半贡献为 0
  2. 包在整个旧串外面
    新串 = ( + 旧串 + )
    这对新括号把之前所有的 i-1 对括号都包了进去。
  • 旧串的每个字符的高度都会 +1,旧串长度为 2*(i-1),所以总高度增加了 2*(i-1)
  • 转换成半贡献,就是 i-1

所以,第 i 对括号如果选择"包外面",它能提供的半贡献就是 i-1
有人问半贡献是啥?

每一对 () 本身至少占 1 个单位的高度。所以 n 对括号,最低高度是 n(全部并排)

当你把一对新括号 包在外面 时,它不会只增加 1 个高度。因为它把里面所有的括号都"抬高了一层"。

因为每次"包在外面"带来的增量都是 偶数2x)。既然是偶数,我们就可以把它 对半砍 ,只记录里面的 x 是多少。

  • 这个 x ,就是所谓的 "半贡献"
  • 题目里的 need = (k - n) / 2,就是我们需要凑出来的所有"半贡献"的总和
    所以对于每一个括号我们进行选择嵌套不嵌套的选择,我们肯定是这样凑到(k-n)/2个半贡献,就是从最后一个括号开始遍历,看看他需不需要嵌套括号,然后要是嵌套括号的话它会减少一定的半贡献,然后接着遍历,知道(k-n)/2==0就结束,我们对于需要嵌套的进行标记就行了
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;
// bool vis[INF]={false};
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;
}
void solve()
{
	int n,k;
	cin>>n>>k;
	if(k<n||k>n*n){
		cout<<-1<<endl;
		return;
	}
	if((k-n)%2!=0){
		cout<<-1<<endl;
		return;
	}
	vector<bool> vis(n+1,false);
	int need=(k-n)/2;
	for(int i=n;i>=1;i--)
	{
		if(need==0) break;
		if(i-1<=need){
			vis[i]=true;
			need-=(i-1);
		}
	}
	deque<char>dq;
    for (int i=1;i<=n; i++) {
        if(vis[i]){
            dq.push_front('(');
            dq.push_back(')');
        } else {
            dq.push_back('(');
            dq.push_back(')');
        }
    }
	for(char c:dq) cout<<c;
	cout<<endl;
	// cout<<fixed<<setprecision(x)<<
}
signed main()
{
	IOS;
	int _=1;
	cin>>_;
	while(_--)
	solve();
	return 0;
}

有一点值得注意的是,这里我们不能用string,因为一次一次的前加或者后加字符有点耗时间,避免这个时间损耗,我们用双端队列来实现


H题

H-小苯的镜像符文_河南萌新联赛2026第(四)场:南阳理工学院

吓人的H题,自从学长说这题有点难理解之后就没敢碰它,但不信邪的我还是来看了看,发现别有洞天!
思路:首先我们知道题目所说的拼接方法无非只有两个

1:通过一个一个拼接,每一个拼接字符有一个价格

2:通过选取一段区间,我们可以直接把这个区间翻转过来补充到串后面,花费k

那么我们分析出来,后面这个方法的不就是回文嘛,而且还是偶数回文,因为问你是复制前面区间,那么无论前面是偶数巨剑还是奇数区间,后面再补充一个那么这个回文肯定是一个偶数区间嘛。

那么我们的解决方法就是正常我们一个一个拼接,然后对于每一个字符,我们可以让它进行两边扩展:

就是说比如我们现在遍历到了字符i,那么我们以这个字符和下一个字符为中心,找字符i的左边的字符和右边的字符相等的长度,也就是我们以i和i+1,为中心进行两边扩展找回文,找到了,我们就比较这一段用方法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=(1LL<<60);
void solve()
{
	int n,k;
	cin>>n>>k;
	string s;
	cin>>s;
	vector<int> cost(26);
	for(int i=0;i<26;i++) cin>>cost[i];
	vector<int> dp(n+1,INF);
	dp[0]=0;
	for(int i=0;i<n;i++){
		dp[i+1]=min(dp[i+1],dp[i]+cost[s[i]-'a']);
		for(int l=i-1,r=i;l>=0&&r<n&&s[l]==s[r];l--,r++){
			dp[r+1]=min(dp[r+1],dp[i]+k);
		}
	}
	cout<<dp[n]<<endl;
	// cout<<fixed<<setprecision(x)<<
}
signed main()
{
	IOS;
	int _=1;
	cin>>_;
	while(_--)
	solve();
	return 0;
}

总算补完题了,这周补题速度有点慢了,马上结束了才补完,庆幸也是完成这项任务了!

相关推荐
土司大王1 小时前
LeetCode hot100——两数之和
数据结构·算法·leetcode
luj_17681 小时前
大航海时代:沉浸式财商实战沙盒
c语言·开发语言·网络·经验分享·算法
Navigator_Z1 小时前
LeetCode //C - 1200. Minimum Absolute Difference
c语言·算法·leetcode
wabs6662 小时前
关于字符串【力扣344.反转字符串的思考】
数据结构·算法·leetcode
LuminousCPP2 小时前
数据结构基础篇(二):顺序表与链表全方位对比|从内存布局到 CPU 缓存理解底层差异
c语言·数据结构·经验分享·链表·缓存
有点。2 小时前
C++二叉树(一)
开发语言·数据结构·c++
民乐团扒谱机3 小时前
【微实验】谐波乘积谱(HPS)算法深度解析:原理、数学与代码实现
开发语言·人工智能·python·算法·语音识别·音乐
Nil2083 小时前
leetcode 73矩阵置0
算法·leetcode·矩阵
Lazionr3 小时前
stack与queue:底层实现与容器适配器
开发语言·数据结构·c++