河南萌新联赛2026第(四)场:南阳理工学院

河南萌新联赛2026第(四)场:南阳理工学院

补题入口直接点题目即可

难度:

签到:M , G

easy:L , J

mid:D , H , I

mid - hard:C , B , E , F

hard:K , A

M-噢耶,奶奶的龙!!!

高数题,有界乘无穷小算出来极限是0,输出就好了

G-你逃不过我你信不信

题目:

输入一个正整数n,求1到n的阶乘和的最后四位数字(不够4位的向前补0)

思路:

阶乘和,如果阶乘里有10000之后那往后再怎么求和也不会改变最后四位的数值了,所以你可以想一下,2,5,10,15,20,这里的5因子已经有四个,分别都乘2,那就是四个0了,所以在阶乘20之后的数后面四位就不会改变了

代码:

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

void solve()
{
	int n; cin>>n;
    if(n>=20){
        cout<<"0313"<<endl;
        return;
    }
    int m=1,num=0;
    for(int i=1;i<=n;i++){
        m*=i;
        num+=m;
	} 
    int p=num%10000;
    int pp=p;
    int k=0;
    while(pp>0){
        pp/=10;
        k++;
    }
    while(1){
        if(k<4){
            cout<<0;
            k++;
        }else{
            break;
        }
    }
    cout<<p;
	// cout<<fixed<<setprecision(x)<<
}
signed main()
{
	IOS;
	int _=1;
	//cin>>_;
	while(_--)
	solve();
	return 0;
}

好像ic省赛有这道题

L-A × B

高精度乘法的模板题,赛时忘记咋写了被自己气哭了

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

const int INF=1e6+5;
void solve()
{
    string s1,s2;
    cin>>s1>>s2;
    int l1=s1.size();
    int l2=s2.size();
    reverse(s1.begin(),s1.end());
    reverse(s2.begin(),s2.end());
    vector<int> a(l1+l2,0);
    for(int i=0;i<l1;i++){
        for(int j=0;j<l2;j++){
            a[j+i]+=(s1[i]-'0')*(s2[j]-'0');
        }
    }
    for(int i=0;i<l1+l2-1;i++){
        a[i+1]+=a[i]/10;
        a[i]=a[i]%10;
    }
    while(a.size()>1&&a.back()==0) a.pop_back();
    for(int i=a.size()-1;i>=0;i--){
        cout<<a[i];
    }
	// cout<<fixed<<setprecision(x)<<
}
signed main()
{
	IOS;
	int _=1;
	// cin>>_;
	while(_--)
	solve();
	return 0;
}

J-小苯的星轨

题目:

平面直角坐标系中有 n 颗星星,第 i 颗星星位于整点(xi,yi)

保证所有星星的位置两两不同,但允许某颗星星位于原点 (0,0)

小苯会选择两颗不同的星星,组成一个无序星星对。如果经过这两颗星星的直线同时经过原点 (0,0)那么称这个星星对是合法的

1、 选择第 i 颗和第 j 颗星星,与选择第 j 颗和第 i 颗星星是同一个星星对

2、 如果两颗星星中有一颗位于原点,那么这个星星对一定合法

3、 由于所有星星的位置两两不同,任意两颗星星都能确定唯一一条直线

请计算合法无序星星对的数量

思路:

原点是比较特殊的,所以要单独处理,两个点想要共线就要斜率相同,所以我们用map把斜率都存起来就可以知道多少点可以构成这个斜率的直线,在算斜率时要化成最简方向向量,求最大公约数去化简,然后统一符号,确保方向相反的两个向量被映射到同一个键,然后C(cnt, 2) = cnt * (cnt - 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;

// int gcd(int a,int b){
//     a=abs(a),b=abs(b);
//     while(b){
//         int t=a%b;
//         a=b;
//         b=t;
//     }
//     return a;
// }

void solve(){
    int n;
    cin>>n;
    map<pii,int>mp;
    int a=0;
    int num=0;
    for(int i=1;i<=n;i++){
        int x,y; cin>>x>>y;
        if(x==0&&y==0){
            num+=n-1;
        }else{
            int g=__gcd(x,y);
            x=x/g;
            y=y/g;
            mp[{x,y}]++;
        }
    }
    for(auto &pr:mp){
        int cnt=pr.se;
        num+=cnt*(cnt-1)/2;
    }
    cout<<num<<endl;
}
signed main(){
	IOS;
	int _=1;
	cin>>_;
	while(_--) solve();
	return 0;
}

D-小圆爱玩龙龙(Easy)

题目:

在N件物品中选择一些购买,每个道具有价格wi,和快乐值vi 允许免费拿走一个,其他道具最多只能拿一次,且总花费不能超过W,最多可以获得多少快乐值

思路:

只能拿一次,就是01背包问题,但是多了一个条件可以免费拿一个,那就枚举免费拿每一件物品,其他的物品用01背包求出W最大能多少快乐值

代码:

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

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, W;
    cin >> n >> W;

    vector<int> w(n), v(n);
    //读入每件物品重量w[i],价值v[i]
    for (int i = 0; i < n; i++) {
        cin >> w[i] >> v[i];
    }

    int ans = 0;

    // f:枚举哪一件物品作为【免费拿走】的物品
    // f从0到n‑1,依次假设第f件免费
    for (int f = 0; f < n; f++) {
        vector<int> dp(W + 1, 0); // dp[j]:花费j元能拿到的最大快乐值

        //遍历所有物品
        for (int i = 0; i < n; i++) {
            if (i == f) continue; //免费的这件跳过,不参与背包(不用花钱买)

            //标准01背包倒序循环
            for (int j = W; j >= w[i]; j--) {
                dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
            }
        }
        // dp[W]:剩下物品用最多W元得到的最大价值;再加上免费物品的价值v[f]
        ans = max(ans, dp[W] + v[f]);
    }

    cout << ans << '\n';
    return 0;
}

H-小苯的镜像符文

题目:

一个空的串,要求绘制一个长度为n的字符串s,可以执行两种操作

  1. 手动绘制,在字符串末尾绘制一个小写英文字母,手动绘制分别有能量消耗
  2. 镜像法术,选择当前字符串的一个非空后缀,将它翻转追加到字符串末尾,一次消耗k点能量

不能删除或修改已经绘制好的字符,求出绘制出s所需的最少能量

思路:

操作二其实就是找回文字符串,如果操作2的k点能量比操作1手动绘制要小,那自然要用操作二,所以操作二就是在字符串s中找回文字符串,每次从第i个字符开始扩展L- -R++只要sL==sR,就可以直接在位置i跳到位置R,耗费k点能量,

然后用dp一个数组记录每个前缀的最小代价,然后枚举所有可能的转移,取最小值

这里为什么用dp讲一下自己的理解吧,首先还是因为这题要考虑全局的情况,就是一次镜像虽然跨度大但是能量消耗也可能大,手绘的话可能跨度小,但是累计起来可能更便宜所以需要全局衡量不能贪心,然后每个位置耗费能量的最小值一定是构造前面字符的最优解,想得到现在的最优状态肯定是由小的状态组成的,就是要保证最优子结构,然后题目中给了两种状态转移,同时从左往后绘制的过程和状态的计算同步,一定是之前的状态推出之后的状态,满足状态的一种"单调性"

所以用dp去写,第一个字符只能手绘,后续看字符串s判断是不是回文串,再用两种操作所需要的能量去更新当前状态的最小值,然后每次都选择最小值单向递推最终得到答案

代码:

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

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    int T;
    cin >> T;
    while (T--) {
        int n;
        int k;
        cin >> n >> k;

        string s;
        cin >> s;

        vector<int> cost(26);
        for (int i = 0; i < 26; ++i) cin >> cost[i];

        const int INF = (1LL << 62);
        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] << '\n';
    }
    return 0;
}

I-小苯的括号高度

题目:

思路:

题目很简单,最大高度就是n2 最小呢就是n 所以在这范围之外的直接输出-1 即可

为什么呢:

n = 3,串 ((())) 为例

高度序列为:[1, 2, 3, 2, 1, 0]

高度和 = 1 + 2 + 3 + 2 + 1 + 0 = 9

这不久看出来了,除了最高的两两配对就刚刚好是n2

任何合法括号串的高度和与 n 的差恒为偶数,所以 k-n 必须是偶数

贪心构造:

先令目标值减去最小高度和,再除以 2,得到还需要增加的贡献 ,当处理第 m 对括号时,如果选择"包在外面",就会额外贡献 m-1(内部每一个高度都加1),我们依次对于每一对括号,都有两种选择吗,直接放在末尾额外贡献0,包在外面额外贡献m-1,所以问题变成:从 0,1,2,...,n−1中选一些数,使它们的和等于目标贡献由于这些数可以表示从 0 到最大值之间的所有整数,因此从大到小贪心选择即可

代码:

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

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int T;
    cin >> T;

    while (T--) {
        long long n, k;
        cin >> n >> k;

        if (k < n || k > n * n || (k - n) % 2) {
            cout << -1 << '\n';
            continue;
        }

        long long need = (k - n) / 2;//算出需要增加的贡献
        vector<int> wrap(n + 1);

        for (int m = n; m >= 1; m--) {
            if (m - 1 <= need) {//从大到小贪心,最终一定能凑出need
                wrap[m] = 1;
                need -= m - 1;
            }
        }

        deque<char> dq;

        for (int m = 1; m <= n; m++) {
            if (wrap[m]) {
                dq.push_front('(');
                dq.push_back(')');
            } else {
                dq.push_back('(');
                dq.push_back(')');
            }
        }

        for (char c : dq) cout << c;
        cout << '\n';
    }

    return 0;
}
相关推荐
To_OC3 小时前
LC 239 滑动窗口最大值:从暴力超时到单调队列一遍过
javascript·算法·leetcode
.道阻且长.4 小时前
9.LeetCode算法习题讲解--滑动窗口--无重复字符的最长字串
算法·leetcode·职场和发展·哈希算法
余额瞒着我当琳5 小时前
C++--深拷贝三件套 + swap + 写时拷贝 + vector 扩容 + reserve
java·开发语言·c++
ltl5 小时前
HNSW:图索引如何击败树索引
算法
ShineWinsu6 小时前
对于C++:布隆过滤器(bloomfilter)的详细解析
c++·面试·位图·位运算·布隆过滤器·海量数据·比特位
曹牧7 小时前
C#:数字的定义和表示方式
算法·c#
Nil2087 小时前
leetcode 138随机链表的复制
算法·leetcode·链表
疯狂打码的少年9 小时前
【数据结构】图的遍历:深度优先搜索(DFS)
数据结构·笔记·算法·深度优先