SMU Spring 2023 Contest Round 7
A. Programming Contest
签到题.
输入输出读完应该就懂了:
从y1枚举到y2,若枚举的年份不在停办年份里则答案加一
void solve() { int n,m; cin >> n; vector<int> a(N),year(N); cin >> m; for(int i = 0;i < m;i++){ int y; cin >> y; year[y] = 1; } int y; cin >> y; int ans = 0; for(int i = n;i <= y;i ++) if(!year[i]) ans++; cout << ans << endl; }
C. Trading
每次应该从价格最便宜的商店购买货物,并卖给价格最贵的商店。用双指针模拟这一贪心策略即可.
#include<bits/stdc++.h> using namespace std; #define LL long long void solve(){ LL n; cin >> n; vector<pair<LL,LL>> a; for(LL i = 0;i < n;i ++){ LL x,y; cin >> x >> y; a.push_back({x,y}); } LL sum = 0; sort(a.begin(), a.end()); for(LL i = 0, j = n - 1; i < j; ){ LL x = min(a[i].second, a[j].second); sum += (a[j].first - a[i].first) * x; a[i].second -= x; a[j].second -= x; if(a[i].second == 0) i++; if(a[j].second == 0) j--; } cout << sum << endl; } int main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); LL T; cin>>T; while(T--){ solve(); } return 0; }
D. New Houses
如果已知 \(k (2\le k \le n)\)个人有邻居,剩下的人没有邻居,怎样选择有邻居的人才能使总满意度最大化?
这是一个经典问题。先假设所有人都是没邻居的,得到总满意度 \(\sum\limits_{i = 1}^n b_i\) 。当第 \(i\) 个人从没邻居变成有邻居时,总满意度将增加 \((a_i - b_i)\)。因此选择 \((a_i - b_i)\) 最大的 \(k\) 个人变成有邻居的即可。排序后可以在 \(\mathcal{O}(n)\)的复杂度内一次性算出 $k = 2, \cdots, n $ 的最大总满意度。
如果 \(k\) 个人有邻居,剩下的人没有邻居,这样的布局至少需要 \(k + 2(n - k) = 2n - k\) 栋房子(即有邻居的人都住在最左边,然后每隔一栋房子住一个没邻居的人)。因此只有满足 \(2n - k \le m\) 才能考虑。
最后,别忘了考虑所有人都没有邻居的情况。这要求 \(m \ge 2n - 1\)。
#include <bits/stdc++.h> #define endl '\n' #define int long long using namespace std; const int N = 1e6+10, M = 998244353; typedef unsigned long long ll; typedef pair<int,int> PII; int n,m,t,k; map<int,int> mp; void solve() { cin >> n >> m; vector<int> A(n + 1), B(n + 1),ve; for(int i = 1;i <= n;i ++){ cin >> A[i] >> B[i]; ve.push_back(A[i] - B[i]); } sort(ve.begin(), ve.end()); int ans = 0, now = 0; for(int i = 1;i <= n;i ++) now += B[i]; if(m >= 2 * n - 1) ans = now; now += ve[n - 1]; for(int i =2;i <= n;i ++){ now += ve[n - i]; if(2 * n - i <= m) ans = max(ans, now); } cout << ans << endl; } signed main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int Ke_scholar = 1; cin >> Ke_scholar; while(Ke_scholar--) solve(); return 0; } /* */
I. Path Planning
假设答案为 \(x\),那么存在一条路径,使得从 \(0\) 到 \((x-1)\) 的每个整数都在路径上。这一条件满足二分性,因此我们可以二分答案 \(x\),并检查是否存在这样的路径。
由于每一步只能往右或者往下走,因此将路径上每个格子的坐标按行为第一关键字,列为第二关键字排序后,排在前面的坐标的列编号,一定小于等于排在后面的坐标的列编号。
因此,将从 0 到 \((x-1)\) 的每个整数所在的格子的坐标排序,并检查列编号是否满足以上条件,即可判断是否存在一条路径,使得这些整数都在路径上。实际实现时,不需要使用排序函数。只要依此枚举每个格子,若格子里的整数小于 \(x\) 则把格子加入 vector
,这样得到的 vector
就已经按枚举的顺序排序了。
#include <bits/stdc++.h> #define inf 0x3f3f3f3f #define endl '\n' #define int long long using namespace std; const int N = 1e6+10, M = 998244353; typedef unsigned long long ll; typedef pair<int,int> PII; int n,m,t,k,a[N]; // 将从 0 到 x - 1 所在的格子坐标“排序”,检查前面的列坐标是否小于等于后面的列坐标 bool check(int x){ // 实际实现时,不需要使用排序函数, // 直接按顺序枚举每个格子,若格子里的整数小于 x 则把格子加入 vector, // 这样得到的 vector 就已经按枚举的顺序排序了 // 而且甚至连 vector 也不用真的维护, // 因为我们只关心 vector 最后一个元素的列坐标,和当前列坐标的大小关系, // 直接用变量 last 维护最后一个元素的列坐标即可 int last = 0; for(int i = 0;i <n;i ++){ for(int j = 0;j < m;j ++){ if(a[i * m + j] < x){ if(last > j) return false; last = j; } } } return true; } void solve() { cin >> n >> m; for(int i = 0;i < n;i ++) for(int j = 0;j <m ;j++) cin >> a[i * m + j]; int l = 0, r = n * m; while(l < r){ int mid = (l + r + 1) >> 1; if(check(mid)) l = mid ; else r = mid - 1; } cout << l << endl; } signed main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int Ke_scholar = 1; cin >> Ke_scholar; while(Ke_scholar--) solve(); return 0; } /* */
K. Peg Solitaire
因为数据范围很小,直接模拟暴力就能过
#include<bits/stdc++.h> using namespace std; const int N = 1e6+10; #define int long long int ans = 100; int u[] = {0,2,0,-2}; int v[] = {2,0,-2,0}; int uu[] = {0,1,0,-1}; int vv[] = {1,0,-1,0}; int n,m,k; void dfs(int x,int y, vector<vector<int>>& gg ){ for(int i = 0;i < 4;i ++){ int dx = u[i] + x; int dy = v[i] + y; int d1 = uu[i] + x; int d2 = vv[i] + y; if(dx > 0 && dy > 0 && dx <= n && dy <= m && gg[d1][d2] && !gg[dx][dy]){ gg[dx][dy] = 1; gg[x][y] = gg[d1][d2] = 0; for(int i = 1;i <= n;i ++){ for(int j = 1;j <= m;j ++){ if(gg[i][j]){ auto ggg = gg; dfs(i,j,ggg); } } } gg[dx][dy] = 0; gg[x][y] = gg[d1][d2] = 1; } } int sum = 0; for(int i = 1;i <= n;i ++) for(int j = 1;j <= m;j ++) if(gg[i][j]) sum++; ans = min(ans, sum); return ; } void solve(){ ans = 100; cin >> n >> m >> k; vector<vector<int> > g(n + 1, vector<int> (m + 1, 0)); for(int i = 0;i < k; i++){ int x,y; cin >> x >> y; g[x][y] = 1; } for(int i = 1;i <= n;i ++){ for(int j = 1;j <= m;j ++){ if(g[i][j]){ auto gg = g; dfs(i,j,gg); } } } cout << ans << endl; } int32_t main() { ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr); int T; cin>>T; while(T--){ solve(); } return 0; }
其余题解参考2023 广东省大学生程序设计竞赛 - SUA Wiki
因为咱很懒,所以有的题解直接拿来用了😣
本文作者:Ke_scholar
本文链接:https://www.cnblogs.com/Kescholar/p/17506290.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步