CF Round 775 Div2 题解

A题 Game

给定一个长度为 n 的一维线性地图,位置 i 处可能是陆地或者水。

现在我们要从位置 1 到达位置 n 处(保证这两个地方都是水),我们有两种方式:

  1. 如果位置 i 和位置 i+1 都是陆地,那么可以不耗费代价来互相移动
  2. 可以从位置 x 跳到位置 y,消耗代价为 |yx| (该操作至多进行一次)

问需要花费至少多少代价来从位置 1 到达位置 n

1n100

从头尾分别延伸最长的连续陆地串,然后中间直接跳即可。

#include<bits/stdc++.h> using namespace std; const int N = 110; int n, a[N]; int solve() { cin >> n; for (int i = 1; i <= n; ++i) cin >> a[i]; // bool flag = true; for (int i = 1; i <= n; ++i) if (a[i] == 0) flag = false; if (flag) return 0; int l, r; for (int i = 1; i <= n; ++i) if (a[i] == 0) { l = i - 1; break; } for (int i = n; i >= 1; i--) if (a[i] == 0) { r = i + 1; break; } return r - l; } int main() { int T; cin >> T; while (T--) cout << solve() << endl; return 0; }

B题 Game of Ball Passing (数学)

建议直接看原题面

我们对整个数组从小到大排个序,记整个数组前 n1 个元素之和为 L,最大元素的值为 R

L+1R 的时候,不难构造出只含有一个球的方案。

L+1<R 时,我们发现,每次一个球都会使得 RL 的差值减小 1,所以答案为 RL

#include<bits/stdc++.h> using namespace std; #define LL long long const int N = 100010; int n; LL a[N]; int solve() { cin >> n; for (int i = 1; i <= n; ++i) cin >> a[i]; sort(a + 1, a + n + 1); if (a[n] == 0) return 0; LL L = 0, R = a[n]; for (int i = 1; i < n; ++i) L += a[i]; return max(R - L, 1LL); } int main() { int T; cin >> T; while (T--) cout << solve() << endl; return 0; }

C题 Weird Sum(前缀和)

给定一张 nm 列的地图,每个格子都有一个自己的颜色 ci,j

我们记同一颜色 x 的格子的集合为 Sx,那么 f(Sx) 为集合内格子两两曼哈顿距离之和,试求出 xMf(Sx) 的值。(M 为地图中所有颜色之和)

1nm,nm106,1ci,j106

这个显然,我们开 106 个 vector,讲相同颜色的格子放入对应颜色的 vector 里面,然后直接对每个 vector 求解即可。

不过,我们平方枚举肯定不行,得优化到线性复杂度。

我们考虑坐标仅有一维的情况,那么我们直接将坐标排个序,然后做一次前缀和,按照算贡献的方式来统计答案,就能够将平方枚举优化到线性。

i=1n1j=1+1n|xjxi|=i=1n1(j=i+1nxj(ni)xi)

对于二维的曼哈顿距离,由于两轴坐标互相独立,互不影响,所以我们直接分别排序统计后相加即可。

#include<bits/stdc++.h> using namespace std; #define LL long long const int C = 100010; int n, m; vector<pair<int, int> > color[C]; LL x[C], y[C], xx[C], yy[C]; LL solve(int c) { vector<pair<int, int> > &arr = color[c]; int cnt = 0; for (auto it : arr) x[++cnt] = it.first, y[cnt] = it.second; sort(x + 1, x + cnt + 1); sort(y + 1, y + cnt + 1); for (int i = 1; i <= cnt; ++i) xx[i] = xx[i - 1] + x[i], yy[i] = yy[i - 1] + y[i]; LL res = 0; for (int i = 1; i < cnt; ++i) { int len = cnt - i; res += (xx[cnt] - xx[i]) - x[i] * len; res += (yy[cnt] - yy[i]) - y[i] * len; } return res; } int main() { //read cin >> n >> m; for (int i = 1; i <= n; ++i) for (int j = 1, c; j <= m; ++j) { cin >> c; color[c].push_back(make_pair(i, j)); } //solve LL ans = 0; for (int i = 1; i < C; ++i) ans += solve(i); cout << ans << endl; return 0; }

D题 Integral Array(倍数枚举)

给定一个数组 {an},问是否对于内部任意两个元素 x,y(xy)xy 也在数组内?

1n106,1aic106

一个偏暴力的 TLE 写法

我们将数组排个序并 unique 一下,然后从小到大依次将数放进去,每次加入一个新数字的时候,只枚举 ai 范围内的数,如果这个数存在,就看看整除的结果在不在数组内;如果不在,则看范围 [L,R] 之内的数是否存在(L,R 满足 ai 除以区间内的数得到的结果都等于这个数,可以 O(1) 的计算 L,R)。考虑到单点修改和区间查询,所以我们维护一个 set 或者树状数组/线段树。

总复杂度 O(nclogc),对于 105 的数据还能挣扎一下,但是 106 属实有点为难了。

正解:倍数枚举

我们一开始就创建好 vis 数组并做一次前缀和(我们上面那个方法是动态插入的,所以有一个 O(logn) 的复杂度,这里直接是一开始全部处理好,然后实现 O(1) 查询)。

我们枚举每一种值,倘若这个值存在,我们记为 x,那么我们直接枚举 yx 的值,记为 k,那么有 kxy<k(x+1)。我们看看区间 [kx,kx+x1] 内是否存在数,如果存在,那么我们就要查询一下 k 是否存在了。

这个的复杂度就是纯 O(n+cc),其实也就是少了一个 O(logc) 的复杂度。

#include<bits/stdc++.h> using namespace std; const int N = 1000010; int n, c, a[N]; // int vis[N], pre[N]; inline bool query(int L, int R) { return pre[R] > pre[L - 1]; } // bool solve() { //read scanf("%d%d", &n, &c); for (int i = 1; i <= n; ++i) scanf("%d", &a[i]); //init memset(vis, 0, sizeof(int) * (c + 1)); for (int i = 1; i <= n; ++i) vis[a[i]] = 1; for (int i = 1; i <= c; ++i) pre[i] = pre[i - 1] + vis[i]; //solve for (int x = 1; x <= c; ++x) { if (!vis[x]) continue; for (int k = 1; k * x <= c; ++k) if (query(k * x, min(c, k * x + x - 1)) && !vis[k]) return false; } return true; } int main() { int T; scanf("%d", &T); while (T--) puts(solve() ? "Yes" : "No"); return 0; }

__EOF__

本文作者cyhforlight
本文链接https://www.cnblogs.com/cyhforlight/p/15975989.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   cyhforlight  阅读(53)  评论(3编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示