SMU Summer 2024 Contest Round 3
SMU Summer 2024 Contest Round 3
寻找素数对
题意
给你一个偶数,找到两个最接近的素数,其和等于该偶数。
思路
处理出 1e5 以内的素数,然后遍历,更新最接近的答案。
代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
vector<int> euler_range(int n) {
vector<int> phi(n + 1), prime;
vector<bool> is_prime(n + 1, true);
is_prime[1] = 0, phi[1] = 1;
for (int i = 2; i <= n; i++) {
if (is_prime[i]) prime.push_back(i), phi[i] = i - 1;
for (int j = 0; j < (int)prime.size() && i * prime[j] <= n; j++) {
is_prime[i * prime[j]] = 0;
if (i % prime[j]) phi[i * prime[j]] = phi[i] * (prime[j] - 1);
else {
phi[i * prime[j]] = phi[i] * prime[j];
break;
}
}
}
return prime;
}
const int N = 1e5;
auto pr = euler_range(N);
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int x;
set<int> s(pr.begin(), pr.end());
while (cin >> x) {
int a = 0, b = 0;
for (auto i : pr) {
if (i > x) break;
if (s.count(x - i)) {
if (!a) a = i, b = x - i;
else if (abs(x - i - i) < abs(a - b))
a = i, b = x - i;
}
}
if (a > b) swap(a, b);
cout << a << ' ' << b << '\n';
}
return 0;
}
抱歉
题意
平面上有 n 个点,每个点至少有 2 条曲线线段连接,所有曲线线段不相交,但是任意两点之间可以有多条曲线,问你 n 个点将平面分成了 m 份中存在的曲线线段数量。
思路
满足最小的条件,即每个点都能有两条曲线线段相连的图中最少有 n 条线段。
如图:

可以看出,最小符合条件的连线方式将平面分成了 2 份,又因为两点之间可以有多条曲线,所以每增加一个面只需要加一条曲线即可。
如图:

所以答案就是 \(n+m-2\),记得开longlong。
代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
i64 n,m;
while(cin >> n >> m && n && m){
cout << n + m - 2 << '\n';
}
return 0;
}
搬寝室
题意
从 n 个物品中选出 2k 个物品,每两个物品产生的贡献是其重量差值的平方,求最小的贡献值。
思路
n 个选 2k 个,考虑dp。
因为要求差值的平方最小,所以我们将物品按重量按差值排序,排序后相邻的物品其重量差值相对最小。
然后处理出第 i 个物品与 i + 1 个物品间的差值平方。
设 \(dp_{i,j}\) 为前 i 个物品中搬运 j 次的最小贡献。
对于第 i 个物品,如果选择它,则答案是 i-1 物品与它的贡献加上 \(dp_{i-2,j-1}\) 时的贡献,如果不选,那答案就等于 \(dp_{i-1,j}\) 。
代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, k;
while (cin >> n >> k) {
vector<i64> w(n + 1);
for (int i = 1; i <= n; i ++)
cin >> w[i];
sort(w.begin() + 1, w.end());
vector<vector<i64>> dp(n + 1, vector<i64>(k + 1, LLONG_MAX / 2));
vector<int> val(n + 1);
for (int i = 1; i < n; i ++) {
val[i] = pow(w[i + 1] - w[i], 2);
}
for (int i = 0; i <= n; i ++)
dp[i][0] = 0;
for (int i = 2; i <= n; i ++)
for (int j = 1; j * 2 <= i && j <= k; j ++) {
dp[i][j] = min(val[i - 1] + dp[i - 2][j - 1], dp[i - 1][j]);
}
cout << dp[n][k] << '\n';
}
return 0;
}
Nuts
题意
累加 n 个数大于 10 的部分。
思路
按题意模拟。
代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
int ans = 0;
while (n --) {
int x;
cin >> x;
ans += max(0, x - 10);
}
cout << ans << '\n';
return 0;
}
Happy Birthday! 2
题意
给你一个含有 N 个正整数的序列 A,请你构造两个序列 B 和 C。
设这两个序列长度分别为 x 和 y,则应满足:
- \(1≤,≤\)
- \(1≤_,_≤\) 且两序列均严格递增
- \(B\) 与 \(C\) 互异
- \(∑_{=1}^_{_}≡∑_{=1}^_{C_i}( mod 200)\)
其中互异的定义:若 \(≠\) 或 \(=\) 但存在一个位置 使得 \(_≠_\),则 \(B\) 与 \(C\) 互异。
思路
结论,在 201 个序列中一定存在两个在模 200 的情况余数相等的序列。
证明:若前面 200 个序列的余数两两不等,则第 201 个序列一定与前面某个序列的余数相等。
考虑到当 \(n=8\) 时,其子集序列达到了 256,所以我们可以直接枚举其所有子集,找到满足条件的序列,\(n < 8\) 时也是直接暴力枚举找到答案即可,\(n > 8\) 时必定有解,按照 \(n=8\) 的做法即可。
枚举时注意从 1 开始,因为最少要有一个被选。
代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
const int p = 200;
vector<i64> w(n);
for (auto &i : w)
cin >> i;
n = min(n, 8);
map<int, vector<int>> mp;
auto print = [](vector<int> num) {
cout << num.size() << ' ';
for (auto i : num)
cout << i << " \n"[i == num.back()];
};
for (int i = 1; i < 1 << n; i ++) {
i64 sum = 0;
vector<int> tmp;
for (int j = 0; j < n; j ++) {
if ((i >> j) & 1) {
sum = (sum + w[j]) % p;
tmp.push_back(j + 1);
}
}
if (mp.count(sum)) {
cout << "Yes\n";
print(mp[sum]);
print(tmp);
return 0;
} else
mp[sum] = tmp;
}
cout << "No\n";
return 0;
}
Bowls and Dishes
题意
有 n 道菜和 m 个条件限制,每个条件要求第 \(A_i\) 道菜和第 \(B_i\) 道菜都有人投票才算满足,现有 k 个人,每个人可以在第 \(C_i\) 道菜和第 \(D_i\) 道菜中选择一个投票,现问你每个人投票后满足条件的菜的数量最多有多少。
思路
因为 k 最大只有 16 ,所以直接枚举即可。
0 表示第 i 个人投 \(C_i\) 道菜,1 表示其投 \(D_i\) 道菜。
代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<array<int, 2>> ab(m);
for (auto &[a, b] : ab)
cin >> a >> b;
int k;
cin >> k;
vector<array<int, 2>> cd(k);
for (auto &[c, d] : cd)
cin >> c >> d;
int ans = 0;
for (int i = 0; i < 1 << k; i ++) {
vector<int> dish(n + 1);
for (int j = 0; j < k; j ++) {
dish[cd[j][(i >> j) & 1]] ++;
}
int res = 0;
for (auto [a, b] : ab)
res += (dish[a] && dish[b]);
ans = max(ans, res);
}
cout << ans << '\n';
return 0;
}
Rush Hour 2
题意
给定一张 个点, 条边的无向图,每条边有两个属性 \(c_i,d_i\)。
你现在位于点 1,想要前往点 ,现在的时间是 0。当时间为 时经过第 条边所需的时间是 $c_i+\lfloor \frac{d_i}{t+1}\rfloor $ 。
你可以在城市中停留任意非负整数时间,请求出你到达点 n 所花费的最短时间,如果无法到达,输出 -1。
思路
假设当前时间为 t,经过第 i 座城市,则当前答案为 \(t + c_i+\lfloor \frac{d_i}{t+1}\rfloor\),仔细观察 \(t + \frac{d}{t+1}\),转化为 \(t+1+\frac{d}{t+1}-1\) ,其实就是中学时常说的对勾函数,当且仅当 \(t+1=\sqrt d\) 即 \(t=\sqrt d -1\) 时,取得最小值,所以当走到第 i 座城市的时候,判断一下该时的时间有没有到达 \(\sqrt d -1\),没有就等到这个时候再走,大于这个时间直接走即可,其余就是普通的 \(dijkstra\) 。
代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector g(n + 1, vector<array<int, 3>>());
for (int i = 0; i < m; i ++) {
int u, v, c, d;
cin >> u >> v >> c >> d;
g[u].push_back({v, c, d});
g[v].push_back({u, c, d});
}
vector<i64> dis(n + 1, -1);
using ar2 = array<i64, 2>;
priority_queue<ar2, vector<ar2>, greater<>> Q;
dis[1] = 0;
Q.push({0, 1});
while (Q.size()) {
auto [time, u] = Q.top();
Q.pop();
if (dis[u] < time) continue;
for (auto &[v, c, d] : g[u]) {
i64 t = time, okt = round(sqrt(d)) - 1;
if (t < okt) t = okt;
if (dis[v] == -1 || dis[v] > t + c + d / (t + 1)) {
dis[v] = t + c + d / (t + 1);
Q.push({dis[v], v});
}
}
}
cout << dis[n] << '\n';
return 0;
}
Count Descendants
题意
给出一个 \(n\) 个点的有根树,节点编号为 \(1, 2, \cdots n\),树根为 \(1\),第 \(i\)(\(2 \le i \le n\))号节点的父亲是 \(p_i\)。
给出 \(q\) 个查询,第 \(i\) 个查询包含 \(a_i, b_i\),计算满足以下条件的点 \(u\) 的个数:
1、 \(a_i\) 位于 \(u\) 到 \(1\) 的最短路径上(端点也算);
2、\(u\) 到根上的路径恰好有 \(b_i\) 条边。
\(n, q \le 2 \times 10^5, 0 \le b_i < n\)。
思路
前置知识:时间戳——树中的应用 - 岸南 - 博客园 (cnblogs.com)
由第一个条件可知满足条件的节点一定是 \(a_i\) 自己或是其子孙,判断其子孙可以采用时间戳,若一个点的 \([Tin_u,Tout_u]\) 被 \([Tin_{a_i},Tout_{a_i}]\) 包含。那么 u 就是 \(a_i\) 的子孙节点。
由第二个条件可得,从根节点到 u 的边就是指的 u 在树中的深度。
那么我们按照深度将节点的时间戳存进去,由于 dfs 是深度优先搜索,那么存进去的时间戳一定是升序排列,那么我们只要二分去找到该深度中被 \(a_i\) 的时间戳包含的个数就是我们要求的答案了。
代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector g(n + 1, vector<int>());
for (int i = 2; i <= n; i ++) {
int x;
cin >> x;
g[x].push_back(i);
}
int timer = 0;
map<int, vector<int>> mp;
vector<int> tin(n + 1), tout(n + 1);
auto dfs = [&](auto && self, int u, int d)->void{
tin[u] = timer ++;
mp[d].push_back(tin[u]);
for (auto v : g[u]) {
self(self, v, d + 1);
}
tout[u] = timer ++;
};
dfs(dfs, 1, 0);
int q;
cin >> q;
while (q--) {
int u, d;
cin >> u >> d;
auto end = lower_bound(mp[d].begin(), mp[d].end(), tout[u]);
auto start = lower_bound(mp[d].begin(), mp[d].end(), tin[u]);
cout << end - start << '\n';
}
return 0;
}
To 3
题意
给你一个数,问你最少删除其中哪些位后使得该数能够被 3 整除。
思路
因为数最大只有 1e18,也就是最多只有 18 位,那么枚举一下删掉哪些位即可。
代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
i64 n;
cin >> n;
i64 ans = -1;
i64 len = 1, shi = 1, t = n / 10;
while (t) {
len ++, shi *= 10, t /= 10;
}
for (int i = 0; i < 1ll << len; i ++) {
i64 res = 0, num = 0, t10 = shi;
for (int j = 0; j < len; j ++) {
if (!((i >> j) & 1)) res = res * 10 + (n / t10 % 10);
else num ++;
t10 /= 10;
}
if (res && res % 3 == 0) {
if (ans == -1) ans = num;
else ans = min(ans, num);
}
}
cout << ans << '\n';
return 0;
}
SMU Summer 2024 Contest Round 3的更多相关文章
- 2015 Astar Contest - Round 3 题解
1001 数长方形 题目大意 平面内有N条平行于坐标轴的线段,且不会在端点处相交 问共形成多少个矩形 算法思路 枚举4条线段的全部组合.分别作为矩形四条边.推断是否合法 时间复杂度: O(N4) 代码 ...
- Contest Round #451 (Div. 2)F/Problemset 898F Restoring the Expression
题意: 有一个a+b=c的等式,去掉两个符号,把三个数连在一起得到一个数 给出这个数,要求还原等式,length <= 1e6 三个数不能含有前导0,保证有解 解法: 铁头过题法,分类然后各种判 ...
- Codeforces Round #284 (Div. 2)A B C 模拟 数学
A. Watching a movie time limit per test 1 second memory limit per test 256 megabytes input standard ...
- Sending messages to non-windowed applications -- AllocateHWnd, DeallocateHWnd
http://delphi.about.com/od/windowsshellapi/l/aa093003a.htm Page 1: How Delphi dispatches messages in ...
- Codeforces 240 F. TorCoder
F. TorCoder time limit per test 3 seconds memory limit per test 256 megabytes input input.txt output ...
- cf499B-Lecture 【map】
http://codeforces.com/problemset/problem/499/B B. Lecture You have a new professor of graph theo ...
- Codeforces 240F. TorCoder 线段树
线段树统计和维护某一区间内的字母个数.. . . F. TorCoder time limit per test 3 seconds memory limit per test 256 megabyt ...
- 物联网学生科协第三届H-star现场编程比赛
问题 A: 剪纸片 时间限制: 1 Sec 内存限制: 128 MB 题目描写叙述 这是一道简单的题目,假如你身边有一张纸.一把剪刀.在H-star的比赛现场,你会这么做: 1. 将这张纸剪成两片(平 ...
- [cf contest 893(edu round 33)] F - Subtree Minimum Query
[cf contest 893(edu round 33)] F - Subtree Minimum Query time limit per test 6 seconds memory limit ...
- 水题 Codeforces Round #307 (Div. 2) A. GukiZ and Contest
题目传送门 /* 水题:开个结构体,rk记录排名,相同的值有相同的排名 */ #include <cstdio> #include <cstring> #include < ...
随机推荐
- 架构师必知的11种API性能优化方法
前言 接口性能优化是后端开发人员经常碰到的一道面试题,因为它是一个跟开发语言无关的公共问题. 这个问题既可以很简单,也可以相当复杂. 有时候,只需要添加一个索引就能解决. 有时候,代码需要进行重构. ...
- 【Playwright+Python】系列教程(二)手把手带你写一个脚本
一.如何使用代理方式打开网页 在 playwright.chromium.launch() 中传入 proxy 参数即可,示例代码如下: 1.同步写法: from playwright.sync_ap ...
- .NET 个人博客-发送邮件优化🧐
个人博客-发送邮件优化 前言 之前的发送邮件就弄了个方法,比如回复评论会给评论的人发送邮件,留言回复也是,而且2者的代码有很多一样的地方,比较冗余.然后也是抽空优化一下,思路也是比较常用的工厂+策略模 ...
- Linux 内核:利用of_函数读取设备树结点/属性信息
Linux 内核:利用of_函数读取设备树结点/属性信息 背景 设备树描述了设备的详细信息,这些信息包括数字类型的.字符串类型的.数组类型的,我们在编写驱动的时候需要获取到这些信息. Linux 内核 ...
- 写给rust初学者的教程(二):所有权、生存期
这系列RUST教程一共三篇.这是第二篇,介绍RUST语言的关键概念,主要是所有权和生存期等. 第一篇:写给rust初学者的教程(一):枚举.特征.实现.模式匹配 在写第一篇中的练习代码时,不知道你有没 ...
- Docker部署JavaWeb项目(Tomcat环境)
一.环境准备 1.首先准备一台Centos 7的虚拟机并安装Docker. 2.准备好Tomcat.JDK的安装包以及该java项目的war包. 二.编写Dockerfile Dockerfile是一 ...
- 【PHP】关于fastadmin框架中使用with进行连表查询时setEagerlyType字段的理解
前言 FastAdmin是我第一个接触的后台管理系统框架.FastAdmin是一款开源且免费商用的后台开发框架,它基于ThinkPHP和Bootstrap两大主流技术构建的极速后台开发框架,它有着非常 ...
- 2024 年 Visual Studio 实用插件集合
前言 在软件开发领域,选择正确的工具可以极大地提升开发效率和质量. Visual Studio作为微软推出的强大集成开发环境(IDE),通过安装合适的插件,可以进一步增强其功能,满足开发者多样化的需求 ...
- 24 slide的pdf没有高亮开关
安卓 app slide的pdf没有高亮开关
- ProgressBar 进度控件
在 VB.NET 中,你可以使用 ProgressBar 控件或者自定义的进度提示方法来实现这个功能.以下是一个示例代码,展示如何使用 ProgressBar 控件来显示导入情况: ' 创建一个 Pr ...