河南萌新联赛2026第(四)场:南阳理工学院
2026/8/13 9:44:34 网站建设 项目流程

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

小圆爱玩龙龙(Easy)

题目大意

n nn件物品,背包容量W WW
每件物品:花费w i w_iwi,价值v i v_ivi

规则:

  • 在选出来的物品集合里,最多可以免费拿其中1件,这件免费物品不用花钱。
  • 剩下选的其他物品总花费之和≤ W \le WW
  • 目标:最大化拿到的总价值。

形式化:选集合S SS,选至多一个f ∈ S f\in SfS免费;∑ i ∈ S , i ≠ f w i ≤ W \sum\limits_{i\in S,i\neq f} w_i \le WiS,i=fwiW,求∑ i ∈ S v i \sum\limits_{i\in S}v_iiSvi的最大值。


核心思路

暴力枚举解法(Easy版,图上代码的思路)

枚举哪一件物品当做免费物品,一共n nn种情况:

  1. 假设第f ff件免费:这件物品我们必拿,价值直接加上(v[f]),但是不给它算重量
  2. 剩下其余n-1 件物品,做普通01背包,背包容量依旧是W WW,求出最多价值dp[W]
  3. 总价值 =dp[W] + \(v[f]\)
  4. 在所有f = 0 … n − 1 f=0 \dots n-1f=0n1的结果里取最大值,就是答案。

时间复杂度:O ( n 2 W ) O(n^2W)O(n2W),适合Easy数据;n大的时候会超时,需要二维dp优化版本。

状态解释

dp[j]:不选第f ff件物品,用不超过j jj的钱,能拿到的最大快乐值。手中有j元时有的最大快乐值
因为第f ff件免费直接拿,所以总价值 =dp[W] + \(v[f]\)

核心代码:

dp[j] = max(dp[j], dp[j - w[i]] + v[i]); 花费j时的最大快乐值=在买i之前的最大快乐值+买上i的快乐值

#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); 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; }

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

题目大意:

求1-n的每个数的阶乘之和,输出后4位,不足4位前面补0

核心思路:

n的范围较大,纯算会爆,求后4位为非是让后4位做运算,我们可以把阶乘和阶乘之和每次都%10000,我们发现当n>19时,后4位都是0313,当n>19时直接输出0313,n<19时直接算,输出后4位

#include<bits/stdc++.h> using namespace std; #define int long long const int N=10000; void solve(){ int n; cin>>n; if(n>19){ cout<<"0313"<<endl; return; } int sum=0,sum1=1; ====【阶乘与阶乘之和%10000】==== for(int i=1;i<=n;i++){ sum1*=i%10000; sum+=sum1; sum%=10000; } string s=to_string(sum); int l=s.size(); for(int i=l;i<4;i++)cout<<0; cout<<s; } signed main(){ int _=1; while(_--){ solve(); } }

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

小茉的星轨

题目大意

平面上有n nn颗星星,坐标( x i , y i ) (x_i,y_i)(xi,yi),所有星星坐标互不相同。
选出两颗星星组成无序星星对,合法条件:过这两颗星星的直线经过原点KaTeX parse error: Can't use function '\(' in math mode at position 1: \̲(̲(0,0)\)

特殊规则:

  1. 无序对 ((i,j)) 和 ((j,i)) 算同一个。
  2. 如果两颗星星其中有一颗是原点((0,0)),这个对直接合法。
  3. 求总一共有多少合法无序点对。

几何含义:

  • 两点连线过原点,等价于:两个点在同一条过原点的直线上
  • 一个点((x,y)),把坐标除以gcd ⁡ ( ∣ x ∣ , ∣ y ∣ ) \gcd(|x|,|y|)gcd(x,y),得到最简方向向量,同一条过原点直线上的非原点的点,最简方向向量要么完全相同,要么互为相反数
    例:((2,4))与( − 1 , − 2 ) (-1,-2)(1,2),都在同一条过原点直线。

核心思路

  1. 原点单独处理
    设原点一共有c n t 0 cnt0cnt0个。
    原点和其他任意点配对全部合法,贡献:c n t 0 × ( n − c n t 0 ) cnt0 \times (n-cnt0)cnt0×(ncnt0)

注意:题目保证所有星星坐标互不相同,所以原点最多只会出现1个。

  1. 非原点的点:求方向最简向量
    对一个点((x,y)),先求最大公约数g = gcd ⁡ ( ∣ x ∣ , ∣ y ∣ ) g=\gcd(|x|,|y|)g=gcd(x,y)
    得到n x = x / g , n y = y / g nx=x/g,\; ny=y/gnx=x/g,ny=y/g

⚠坑:本质上是算斜率,让斜率相等的两两结合,但a/b会保留整数,用double也不行,除以最大公约数可以避免,把所有在同一条直线上的点全变为相同的点,统计这样的点有多少个

  1. map统计每一个标准化方向的点的数量c n t cntcnt
    同一个方向上有c n t cntcnt个点,两两配对合法,组合数:C c n t 2 = c n t ∗ ( c n t − 1 ) / 2 \boldsymbol{C_{cnt}^{2}=cnt*(cnt-1)/2}Ccnt2=cnt(cnt1)/2

  2. 答案 = 原点带来的贡献 + 所有方向组合数之和。


#include<bits/stdc++.h> using namespace std; #define int long long #define endl '\n' #define pii pair<int,int> #define fi first #define se second const int N=101; void slove(){ int n; cin>>n; map<pii,int>mp; int ans=0; vector<int>x(n+1,0); vector<int>y(n+1,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 c:mp){ ans+=c.se*(c.se-1)/2; } cout<<ans<<endl; } signed main(){ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); int _; cin>>_; while(_--) slove(); return 0; }

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

高精度乘法,从低位运算

#include<bits/stdc++.h> using namespace std; #define int long long void solve(){ string s1,s2; cin>>s1>>s2; reverse(s1.begin(),s1.end()); reverse(s2.begin(),s2.end()); vector<int>s3(40,0); int l1=s1.size(),l2=s2.size(); for(int i=0;i<l1;i++){ for(int j=0;j<l2;j++){ s3[i+j]+=(s1[i]-'0')*(s2[j]-'0'); } } int len=l1+l2; ===先进位,再% for(int i=0;i<len;i++){ s3[i+1]+=s3[i]/10; s3[i]%=10; } bool ok=false; for(int i=len-1;i>=0;i--){ if(s3[i]!=0)ok=true; if(ok) cout<<s3[i]; } } signed main(){ int _=1; while(_--){ solve(); } }

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询