2026萌新联赛第二场--(河南农业大学)

2026萌新联赛第二场(河南农业大学)补题总结

你的心有一道墙 但我发现一扇窗

偶尔透出一丝暖暖的微光

就算你有一道墙 我的爱会攀上窗台盛放

打开窗你会看到悲伤融化

这时候林俊杰就有疑问了


本场预测难度划分为:

easy:D,H,I

easy-mid:A,B,M

mid:C,E,F,G

mid-hard:K,L

hard:J

这场比赛就有意思了,榜单没有跟着难度走,我打的时候也是这样。在赛时我的做题顺序大概是I H M B D L 很可惜啊,L题确实是棋差一招啊。不过出题人把它放在mid-hard我是实在不太理解啊,这题完全是可以补的呀。当然这个A题出题人把它放在easy-mid也有它的道理。但是在赛时谁看到像语文课文一样的题会想到是一个简单的模拟题呢?况且还很有可能读不懂题目(我就是哈,语文不好,理解不了题意)。当然了,奉劝大家在有时间的情况下还是得多卡看看其他的题,万一你漏掉了一个能做的只是当时不想做那就太可惜了。

题目链接


接下来废话不多说,开始讲题

首先是签到题I

这题就是说让我们取一个右指针,然后遍历的时候看右指针会不会移动,移动条件就是i+a[i]-1>=ans(右指针)

AC代码
int n; cin>>n; vector<int> a(n+1); for(int i=1;i<=n;i++) cin>>a[i]; int r=1; for(int i=1;i<=r;i++) { int shu=i+a[i]-1; if(shu>=n) r=n; else r=max(r,shu); } cout<<r<<endl;

H

H题,这个题是比上一题还简单的签到题,我们对于数组每一个数向上取整累加在一起输出就行了。

int n,x,y; cin>>n>>x>>y; vector<int> a(n); for(int i=0;i<n;i++) cin>>a[i]; int ans=0; if(x==0||y==0){ NO return; } int shu=min(x,y); for(int i=0;i<n;i++){ ans+=((a[i]+shu-1)/shu); } YES; cout<<ans<<endl;

M题

这个M题说实话说的那个多,我在赛时是压根不知道它在讲什么,但是我们通过看这个题目给的实例就基本上能看个半懂,然后根据下面的样例来分析,就知道它讲的是啥了。就是一个数组压缩,111就压缩成[1 3]也就是3个1,那么它让我们输出第k个就很简单了,我们把这个数组还原再输出第k个就行了

int n; cin>>n; vector<int> v(n+1),l(n+1); for(int i=1;i<=n;i++) cin>>v[i]>>l[i]; int T; cin>>T; vector<int> ans; while(T--) { int num; cin>>num; int shu=0; for(int i=1;i<=n;i++) { if(shu+l[i]>=num){ ans.push_back(v[i]); break; }else{ shu+=l[i]; } } } for(int i=0;i<ans.size();i++) cout<<ans[i]<<endl;

B题

B题的思路就是让这个数求和嘛,我们看这个数据很大,所以暴力肯定是超时的,所以我们就得想一个方法给它优化一下,我们不难想到,一个数除以一个数等于1的会有很多数(因为向下取整嘛),然后我们就可以利用这个性质来把这个过程给它截出来,比如说一个数除以7 8 9都等于1,那么我们就把这个7找出来,把这个9找出来,然后9-7+1就是这段长度的长,31就表示了这段长的和,它就可以大大降低我们的时间复杂度,这个思路在赛时想了挺久的,导致这个代码写成了屎山代码,然后在赛后才知道这个思想是分块思想,这题还是一个模板题,优化的代码十分之简短,相比之下我的屎山代码真的是丑爆了

赛时ac代码
// Problem: 不同的商 // Contest: NowCoder // URL: https://ac.nowcoder.com/acm/contest/138554/B // Memory Limit: 1024 MB // Time Limit: 2000 ms // author:世间 // Date:2026-07-27 13:24:51 #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; 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 x,y; cin>>x>>y; if(x==1){ cout<<1<<endl; return; } if(y==1){ cout<<x<<endl; return; } int ans=x; if(y>=x){ y=x; int cnt=2; while(1){ int shu1=x/cnt; if(cnt==y){ ans+=shu1; break; } int cntr=(x/shu1)+1; if(cntr>y) cntr=y+1; int num=(cntr-cnt)*shu1; ans+=num; cnt=cntr; if(cnt>y) break; // cout<<cnt<<' '<<shu1<<' '<<cntr<<' '<<num<<endl; } cout<<ans<<endl; }else{ int cnt=2; while(1) { int shu1=x/cnt; if(cnt==y) { ans+=shu1; break; } int cntr=(x/shu1)+1; if(cntr>y) cntr=y+1; int num=(cntr-cnt)*shu1; ans+=num; cnt=cntr; // cout<<ans<<endl; if(cnt>y) break; } cout<<ans<<endl; } // cout<<fixed<<setprecision(x)<< } signed main() { IOS; int _=1; // cin>>_; while(_--) solve(); return 0; }
优化代码
int x,y;cin>>x>>y; int an=0; if(y>=x) y=x; for(int l=1;l<=y;l++){ int r=x/(x/l); an+=(x/l)*(r-l+1); l=r; } cout<<an<<endl;

D题

这个题本来看到三维切割,这肯定得用到很多算法,什么前缀和,什么差分,什么动态啊,让我很头疼,所以这个题目我在看了一眼只后果断放弃,但是回过头看了一下发现它的数据特别小,我们暴力打一遍直接救过了。暴力思路就是三维数组三层循环没这里就不过多解释了。

AC代码呈上
int w,x,h; cin>>w>>x>>h; int q; cin>>q; int ans=w*x*h; int a[30][30][30]={0}; while(q--) { int x1,y1,z1,x2,y2,z2; cin>>x1>>y1>>z1>>x2>>y2>>z2; for(int i=x1;i<=x2;i++) { for(int j=y1;j<=y2;j++) { for(int k=z1;k<=z2;k++) { if(a[i][j][k]==0){ ans--; a[i][j][k]=1; } } } } } cout<<ans<<endl;

A题

这个题我在赛时也是直接放弃了,文字也是直接劝退主包啊,但是这题我们如果理解了题目就很好做,数据给的也很少了我们可以直接暴力模拟就可以过。

题目大意:我们在(0,0)然后我们不会攻击,但是我们有一个范围,在这个范围是我们的领域,我们的棋子会暴击,就是x从0-4,y从-2-2在这里面我们的棋子会造成基础攻击乘以系数4的伤害,在外面的棋子只会造成基础攻击乘以2的伤害。然后输入几组坐标表示外面初始棋子的位置。然后再输入几组坐标,这几组坐标有限定条件就是如果在我们的领域内的话我们可以观察它的上下左右有没有棋子,要是没有的话我们可以在它的其上下左右都放上一个棋子,但是如果我们这一轮放置的棋子在领域外面就没有这个性质。然后外面再输入m个坐标,这m个坐标是m个敌人,它的位置在哪个棋子的领域内棋子就会爆炸造成伤害(棋子的领域题目i也说了是一个菱形,其实在后面我们可以推出来是abs(x差)+abs(y差)<=2就是在它的领域)。然后我们输出这个伤害。

好吧,其实我解释的也有点过于长了,不过没办法,这题出的长那它的规则也就有些多,只要理解了就很好写了!

你如果理解了题目大意其实就很好写,用一个结构体数组来表示棋子的位置和状态还有暴击的系数,然后用set来看哪个位置会不会已经有棋子了,然后暴力模拟就出来了。

AC代码
// Problem: 天下劫 // Contest: NowCoder // URL: https://ac.nowcoder.com/acm/contest/138554/A // Memory Limit: 1024 MB // Time Limit: 2000 ms // author:世间 // Date:2026-07-28 13:02:28 #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 dx[]={1,-1,0,0}; const int dy[]={0,0,1,-1}; struct node{ int x,y,value; bool ok; }; bool check(int x,int y) { return (x>=0&&x<=4&&y>=-2&&y<=2); } void solve() { int n; cin>>n; vector<node> v; set<pii> st; st.insert({0,0}); for(int i=0;i<n;i++) { int x,y; cin>>x>>y; v.push_back({x,y,4,true}); st.insert({x,y}); } int m; cin>>m; for(int i=0;i<m;i++) { int x,y; cin>>x>>y; if(check(x,y)){ if(st.find({x,y})==st.end()){ v.push_back({x,y,4,true}); st.insert({x,y}); } for(int d=0;d<4;d++) { int nx=x+dx[d]; int ny=y+dy[d]; if(nx==0&&ny==0) continue; if(st.find({nx,ny})==st.end()){ int shu=check(nx,ny)?4:2; v.push_back({nx,ny,shu,true}); st.insert({nx,ny}); } } }else{ if(st.find({x,y})==st.end()){ v.push_back({x,y,2,true}); st.insert({x,y}); } } } int q; cin>>q; for(int i=0;i<q;i++) { int xx,yy; cin>>xx>>yy; int ans=0; vector<int>used; for(int j=0;j<v.size();j++) { if(!v[j].ok) continue; if (abs(v[j].x-xx)+abs(v[j].y-yy)<=2){ ans+=v[j].value*669; used.push_back(j); } } for(auto t:used){ v[t].ok=false; } cout<<ans<<endl; } // cout<<fixed<<setprecision(x)<< } signed main() { IOS; int _=1; // cin>>_; while(_--) solve(); return 0; }

G题

这个题是一个二维前缀和加差分的板子题目吧。就是如果我们熟练于二维差分加前缀和的话这题其实还挺好写的。

首先我们定义一个a数组来标记每一个格子被猫覆盖的数量,如果被一个覆盖就等于1,然后定义一个数组b来表示格子上面有没有猫哈气。初始的ans=2000*2000,然后我们找到一个格子的a数组是1那就表示是一个猫覆盖,我们就可以把它对应的b数组定义为1,然后ans–,然后如果这个格子>1那么我们就把对应的b数组定义为0,因为不管依次去掉哪个猫,这一块都不会从有猫变成无猫,然后ans–。我们用差分是为了节省时间复杂度,而用前缀和是为了方便取区间,比如区间(2,2)到区间(3,3)那么我们想取这个区间只需要
v [ 3 ] [ 3 ] − v [ 1 ] [ 2 ] − v [ 2 ] [ 2 ] + v [ 1 ] [ 1 ] v[3][3]-v[1][2]-v[2][2]+v[1][1]v[3][3]v[1][2]v[2][2]+v[1][1]
所以我们需要用到前缀和的性质。而差分的话我们在输入n个矩形数据的时候想要把所有的二维坐标对应位置都加上1那不现实因为还需要两层循环来实现,那么必定会超时,所以我们用到了差分。

然后用前缀和来实现这个这个格子是1还是0,还是大于1,再根据这个来判断统计被一个猫占领的区域。

AC代码
// Problem: Ha~! // Contest: NowCoder // URL: https://ac.nowcoder.com/acm/contest/138554/G // Memory Limit: 1024 MB // Time Limit: 2000 ms // author:世间 // Date:2026-07-28 09:12:58 #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; int a[2010][2010]={0}; int b[2010][2010]={0}; void solve() { int n; cin>>n; int u[2010]; vector<int> d(n+5); vector<int> l(n+5); vector<int> r(n+5); int ans=2000*2000; for(int i=1;i<=n;i++) { cin>>u[i]>>d[i]>>l[i]>>r[i]; a[u[i]][l[i]]++; a[u[i]][r[i]+1]--; a[d[i]+1][l[i]]--; a[d[i]+1][r[i]+1]++; } for(int i=1;i<=2000;i++) { for(int j=1;j<=2000;j++) { a[i][j]=a[i][j]+a[i-1][j]+a[i][j-1]-a[i-1][j-1]; if(a[i][j]==1){ ans--; b[i][j]=1; }else if(a[i][j]>1){ ans--; b[i][j]=0; } } } for(int i=1;i<=2000;i++) { for(int j=1;j<=2000;j++) { b[i][j]=b[i][j]+b[i-1][j]+b[i][j-1]-b[i-1][j-1]; } } for(int i=1;i<=n;i++) { int num=b[d[i]][r[i]]-b[d[i]][l[i]-1]-b[u[i]-1][r[i]]+b[u[i]-1][l[i]-1]; cout<<ans+num<<endl; } // cout<<fixed<<setprecision(x)<< } signed main() { IOS; int _=1; // cin>>_; while(_--) solve(); return 0; }

L题

这个题感觉没有哪个难,题解说这题是一个字典树板题,但是我们不用他们说的也能写啊。

这里我来一个听独特的方法,仅仅用到哈希表

首先呢,我们知道哈希表可以存储我们想要存的串,但是它的一半串呢,我们不知道怎么办,但是呢,我们可以把它所有的字串全部都存进去,然后呢找的时候也能直接找到,然后当op==3的时候呢,我们再依次把它的字串删了,但是这里我们得删除把它的字串个数删除完,所以这里得改变一下,这个字串通过这个s加了几次我们就删除几次。然后进行模拟就行了

// Problem: 至理名言 // Contest: NowCoder // URL: https://ac.nowcoder.com/acm/contest/138554/L // Memory Limit: 1024 MB // Time Limit: 4000 ms // author:世间 // Date:2026-07-27 14:56:52 #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; void solve() { int n; cin>>n; unordered_map<string,int>mp; while(n--) { int op; cin>>op; if(op==1) { string s; cin>>s; string s1; for(auto x:s){ s1+=x; mp[s1]++; } cout<<mp[s]<<endl; } if(op==2) { string s; cin>>s; if(mp.count(s)) YES else NO } if(op==3){ string s; cin>>s; string s1; int shu=mp[s];//这里我们只删除通过s串加的字串的个数 for(auto x:s){ s1+=x; mp[s1]-=shu; if(mp[s1]==0) mp.erase(s1); } } } // cout<<fixed<<setprecision(x)<< } signed main() { IOS; int _=1; // cin>>_; while(_--) solve(); return 0; }

总结:

​ 有优势有劣势,B题通过数学思维把它做出来了还比较可以,但是其实这题总过题人数不少了,基本上一般人都过了。其次就是差分前缀和,一维现在都不太会用这次直接出一个二维的直接给我干爆炸了,算法方面还得多练啊,其次就是这个L题,这个思想当时有点朝这边想了,都开了两个map来弄了,就差怎么把它的字串删除了,这点学长的思维确实厉害。这次排名比上次进步了,但是还不是太靠前,下次继续努力!