牛客周赛 Round 62 全部题
比赛链接
A 小红的字符移动
statement: 有一个 5 个字符的串,交换前两个字符输出。
solution: 直接模拟即可。由于过于简单就不放代码了。
B 小红的数轴移动
statement: 对于序列 ,小红一开始在 ,每次向原点的方向移动 ,如果到原点就停止。问一共走了多少路程。
solution: 依旧按题意模拟即可。
Code
int n, x, a[100010], ans; int main(){ cin >> n >> x; for(int i = 1; i <= n; i++) cin >> a[i]; int i = 1; while(x != 0){ if(x > 0) ans += a[i], x -= a[i]; else ans += a[i], x += a[i]; i++; if(i > n) break; } cout << ans << endl; return 0; }
C 小红的圆移动
statement:
平面上有 个圆。小红可以进行任意次操作,每次操作可以选择一个圆,将它向任意方向移动若干距离。该操作的代价为该圆面积乘以移动的距离。
小红希望最终包含原点的圆数量不超过 ,请你帮小红算出她操作的最小总代价。。
Solution:
先算出每个圆的面积,第 个圆需要移动的距离等于 。
相乘后排序,把最小的 个数加起来即可。
Code
int n, k; double x[100010], y[100010], r[100010], S[100010], ans; int main(){ cin >> n >> k; for(int i = 1; i <= n; i++){ cin >> x[i] >> y[i] >> r[i]; S[i] = 1.0 * acos(-1) * r[i] * r[i]; S[i] = S[i] * (r[i] - sqrt(x[i] * x[i] + y[i] * y[i])); if(S[i] < 0.0) S[i] = 0.0; } sort(S + 1, S + n + 1); for(int i = n - k; i >= 1; i--) ans += S[i]; printf("%.10lf\n", ans); return 0; }
D 小红的树上移动
statement:
小红拿到了一棵 个节点的树,初始所有节点均为白色。小红初始站在1号节点,并将1号节点染红。小红将不断进行移动直到停止:
1. 若当前节点的邻点中存在白色节点,则小红随机移动到某个相邻的白色节点,并将该节点染红。
2. 若当前节点的邻点中不存在白色节点,则停止移动。
请你帮小红求出最终红点数量的期望。答案在模 意义下计算。。
solution:
观察到从 出发到每个点的路径是唯一的。所以,答案等于每个点到达的概率(设为 )之和。
以 为根,建一棵有根树。然后对于每个节点 ,统计它的儿子数量 。这样对于节点 的儿子 ,有 。
DFS 一遍,算概率的时候求个逆元,最后累加起来就是答案了。
Code:
#define int long longconst int INF = 1e9, MOD = 1000000007; int n, s[100010], ans; vector <int> e[100010]; int qpow(int a, int b){ int t = 1; while(b){ if(b & 1) t = t * a % MOD; a = a * a % MOD; b >>= 1; } return t; } void dfs(int x, int fa, int p){ ans = (ans + p) % MOD; for(int i : e[x]) if(i != fa) s[x]++; int t = qpow(s[x], MOD - 2); for(int i : e[x]) if(i != fa){ dfs(i, x, p * t % MOD); } } signed main(){ cin >> n; for(int i = 1, u, v; i < n; i++){ cin >> u >> v; e[u].push_back(v); e[v].push_back(u); } dfs(1, 0, 1); cout << ans << endl; return 0; }
E&F 小红的中位数查询
statement:
有一个序列 , 次查询,每次查询一个长度为奇数的子区间 的中位数。
,。
solution 1:
先把 离散化(但要输出的是原值)假设权值的区间是 ,然后对于每个权值记 vector:,记录所有等于它的数的下标。
一种暴力的思想是,把 每个数都枚举一次,每次二分求出区间 内数字 的个数。
然后不断累加,直到数字个数大于等于 。
但是这么做的时间复杂度是 的,太慢了。
但我们可以考虑分块!以 为阈值,假设块长 。
大块的部分记录权值分别在 之中的数字个数随着下标增加的前缀和。
小块的部分和上面的暴力想法一样。
对于每次询问,我们一个个大块跑过去,判断加到哪个块的时候,累计的数字个数大于等于 ,记录这个块的左右端点 。
然后我们让 从 往 减少,每次删掉区间 中 的出现次数,直到不满足数字个数大于等于 ,这个区间的中位数就是 了。
时间复杂度 ,可以勉强通过。
Code
#include <bits/stdc++.h> #define int long long using namespace std; const int INF = 1e9;
int n, m, q, sz, blk[100010], mm, s[410][100010]; int a[100010], b[100010], t[400010], l[100010], r[100010]; vector <int> v[100010];
signed main(){ std::ios::sync_with_stdio(false); std::cin.tie(0); cin >> n >> q; for(int i = 1; i <= n; i++) cin >> a[i], b[i] = a[i]; sort(b + 1, b + n + 1); m = unique(b + 1, b + n + 1) - b - 1; sz = (int)sqrt(m); for(int i = 1; i <= n; i++){ a[i] = lower_bound(b + 1, b + m + 1, a[i]) - b; blk[i] = (i - 1) / sz + 1; v[a[i]].push_back(i); } mm = blk[n]; for(int i = 1; i <= n; i++) s[blk[a[i]]][i]++; for(int i = 1; i <= mm; i++) for(int j = 1; j <= n; j++) s[i][j] += s[i][j - 1]; for(int i = 1, now, L, R; i <= n; i++){ cin >> l[i] >> r[i], now = 0; for(int j = 1; j <= mm; j++){ now += s[j][r[i]] - s[j][l[i] - 1]; if(now > (r[i] - l[i] + 1) >> 1){ L = (j - 1) * sz + 1; R = j * sz; break; } } if(now <= (r[i] - l[i] + 1) >> 1) continue; for(int j = R, p1, p2; j >= L; j--){ p2 = upper_bound(v[j].begin(), v[j].end(), r[i]) - v[j].begin(); p1 = lower_bound(v[j].begin(), v[j].end(), l[i]) - v[j].begin(); now -= p2 - p1; if(now <= (r[i] - l[i] + 1) >> 1){ printf("%d\n", b[j]); break; } } } return 0; }
Solution 2
莫队 + 值域分块,
Solution 3
主席树,暂时没写,可以去看其它博客,。
G 小红的数轴移动(二)
statement:
对于序列 ,小红一开始在 ,每次向原点的方向依次移动 ,如果到原点就停止。
你现在可以改变 的顺序,问最少要走多少路程,并输出方案。
。
solution
直接模拟退火,多调几次参数就过了。
下面这份代码可能你再交不一定是满分,但多交几次总可以的(
Code
#include <bits/stdc++.h> using namespace std; mt19937 rnd(time(nullptr)); const double eps = 1e-8; int n, X, now, A[110], P[110], ANS = 100000, a[110], p[110], b[110]; double T; void sa(){ for(int i = 1; i <= n; i++) p[i] = i; shuffle(p + 1, p + n + 1, rnd); for(int i = 1; i <= n; i++) a[i] = A[p[i]]; double T = 3000.0, d; int ss, delta, sum, ans = 100000; while(T > eps){ T *= 0.98; sum = 0; int x = rnd() % n + 1, y = rnd() % n + 1; swap(a[x], a[y]), swap(p[x], p[y]); now = X; for(int i = 1; i <= n; i++){ if(now == 0) break; if(now > 0) now -= a[i], sum += a[i]; else now += a[i], sum += a[i]; } delta = ans - sum; if(delta > 0){ ans = sum; } else{ if(exp(1.0 * (-delta) / T) * RAND_MAX > rand()) swap(a[x], a[y]), swap(p[x], p[y]); } } if(ANS > ans){ ANS = ans; for(int j = 1; j <= n; j++) P[j] = p[j]; } } int main(){ double beg = clock(); cin >> n >> X; for(int i = 1; i <= n; i++) cin >> a[i], A[i] = a[i], p[i] = i; while((clock() - beg) / CLOCKS_PER_SEC < 0.84) // 卡时 sa(); cout << ANS << endl; for(int i = 1; i <= n; i++) cout << P[i] << " "; cout << endl; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?