写在前边

链接:Codeforces Round #702 (Div. 3)

比较简单,但是总是感觉脑子有点转不过弯来。

A. Dense Array

链接:A题链接

题目大意:

在数组中插入若干个数,使得\(\cfrac{max(a[i], a[i + 1])}{min(a[i], a[i + 1])} \leq 2\),问至少需要插入多少个数。

思路

既然是相邻,那么只需要顺序模拟即可,每次把\(min(a[i], a[i + 1])×2\), 直到它的两倍大于等于\(2\)停止,求累计次数。

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <map>
#include <cstring> using namespace std; #define Inf 0x3f3f3f3f
#define PII pair<int, int>
#define P2LL pair<long long, long long>
#define endl '\n' typedef long long LL;
typedef unsigned long long ULL;
typedef vector<long long> VLL;
typedef vector<int> VI; LL gcd(LL a, LL b) {
return b ? gcd(b, a % b) : a;
} const int N = 55; void solve() {
int n;
int a[N];
scanf("%d", &n);
for (int i = 0; i < n; i++) scanf("%d", &a[i]); int res = 0;
for (int i = 1; i < n; i++) {
if (max(a[i], a[i - 1]) > 2 * min(a[i], a[i - 1])) {
int m = min(a[i], a[i - 1]);
while (m * 2 < max(a[i], a[i - 1])) {
res++;
m *= 2;
}
}
}
printf("%d\n", res);
} int main()
{
//ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int t;
scanf("%d", &t);
while (t--) {
solve();
}
return 0;
}

B. Balanced Remainders

链接:B题链接

题目大意:

给定一个有\(n\)(n可以被3整除)个元素的数组,\(c_0,c_1,c_2\)分别表示数组中元素模\(3\)后的余数为\(0, 1, 2\)的数的个数,现在每次操作可以使一个数加\(1\),问最少经过几次操作可以使得\(c_0 == c_1 == c_2\)

思路

可以发现,\(c_0, c_1, c_2\)之间可以进行单一方向的转移,例如模\(3\)余数为\(0\)的数加\(1\)后余数变为\(1\),余数为\(1\)的数加\(1\)后余数变为\(2\),余数为\(2\)的数加\(1\)后余数变为\(0\)

,于是问题就转化成了转移多少次的问题,相邻的转移又一定是最优的。

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <map>
#include <cstring>
#include <unordered_map> using namespace std; #define Inf 0x3f3f3f3f
#define PII pair<int, int>
#define P2LL pair<long long, long long>
#define endl '\n' typedef long long LL;
typedef unsigned long long ULL;
typedef vector<long long> VLL;
typedef vector<int> VI; LL gcd(LL a, LL b) {
return b ? gcd(b, a % b) : a;
} const int N = 3e4 + 10;
int a[N]; void solve() {
int n;
scanf("%d", &n);
unordered_map<int, int> hash;
int cnt0 = 0, cnt1 = 0, cnt2 = 0;
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
hash[a[i] % 3]++;
} int aver = n / 3;
int res = 0;
while (1) {
if (hash[1] == hash[2] && hash[1] == hash[0] && hash[0] == hash[2]) {
break;
}
if (hash[1] < aver) {
hash[0] -= (aver - hash[1]);
res += (aver - hash[1]);
hash[1] = aver;
}
if (hash[2] < aver) {
hash[1] -= (aver - hash[2]);
res += (aver - hash[2]);
hash[2] = aver;
}
if (hash[0] < aver) {
hash[2] -= (aver - hash[0]);
res += (aver - hash[0]);
hash[0] = aver;
}
}
printf("%d\n", res);
} int main()
{
//ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int t;
scanf("%d", &t);
while (t--) {
solve();
}
return 0;
}

C. Sum of Cubes

链接:C题链接

题目大意:

判断一个数\(x\)是否满足\(x = a^3 + b^3 \, (a, b \geq 1)\)

思路

因为数据最大为\(10^{12}\),所以\(a,b \in [1, 10^4)\),所以一种做法是预处理出\(a^3\),然后再\(O(10^4)\)枚举\(b\),\(O(1)\)查找\(a^3\)。

另一种方法是\(O(10^4)\)枚举\(a\),二分\(b\),复杂度\(O(10^4 * log 10^4)\)

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <map>
#include <cstring> using namespace std; #pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline") #define Inf 0x3f3f3f3f
#define PII pair<int, int>
#define P2LL pair<long long, long long>
#define endl '\n' typedef long long LL;
typedef unsigned long long ULL;
typedef vector<long long> VLL;
typedef vector<int> VI; LL gcd(LL a, LL b) {
return b ? gcd(b, a % b) : a;
} void solve() {
LL x;
scanf("%lld", &x);
LL t1;
for (LL i = 1; i <= 10000; i++) {
LL l = 1, r = 10000;
while (l < r) {
LL mid = l + r >> 1;
LL sum = i * i * i + mid * mid * mid;
if (sum > x) r = mid;
else if (sum < x) l = mid + 1;
else {
puts("YES");
return;
}
}
}
puts("NO");
} int main()
{
//ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int t;
scanf("%d", &t);
while (t--) {
solve();
}
return 0;
}

D. Permutation Transformation

链接:D题链接

题目大意:

给定一个数组,用其数据建一棵树,最大的数始终作为树根,树根左侧数构成左子树,右边的数构成右子树,同理选大的作为子树的根,求每个数在树中所处的深度。

思路

\(DFS\)

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <map>
#include <cstring> using namespace std; #define Inf 0x3f3f3f3f
#define PII pair<int, int>
#define P2LL pair<long long, long long>
#define endl '\n' typedef long long LL;
typedef unsigned long long ULL;
typedef vector<long long> VLL;
typedef vector<int> VI; LL gcd(LL a, LL b) {
return b ? gcd(b, a % b) : a;
} const int N = 110;
int a[N];
int res[N];
int n; void build(int l, int r, int depth) {
if (l > r) return; int idx = l;
for (int i = l; i <= r; i++) {
if (a[i] > a[idx]) idx = i;
}
res[idx] = depth;
build(l, idx - 1, depth + 1);
build(idx + 1, r, depth + 1);
} void solve() {
scanf("%d", &n);
for (int i = 0; i < n; i++) scanf("%d", &a[i]); build(0, n - 1, 0); for (int i = 0; i < n; i++) printf("%d ", res[i]);
puts("");
} int main()
{
//ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int t;
scanf("%d", &t);
while (t--) {
solve();
}
return 0;
}

E. Accidental Victory

链接:E题链接

题目大意:

\(n\)个玩家,每人都有一个点数,两个人对战,点数大的获胜,相同点数随机一人获胜,获胜后获得败者的点数,问有哪些人会有获胜的可能性。

思路

一个人要想获胜,那么肯定需要干掉所有的人才可以,首先按照点数给人排序,我们发现对于第i个人它可以直接获得它之前人的所有点数,这里可以用前缀和处理,如果可以赢得比赛,那么他后边的人也一定能赢得比赛,因为他后边的人可以获得更多的点数,所以可以发现有二段性,因此我们可以直接二分出第一个获胜的人,剩下的直接输出即可。

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <map>
#include <cstring> using namespace std; #define Inf 0x3f3f3f3f
#define PII pair<int, int>
#define P2LL pair<long long, long long>
#define endl '\n'
#define score first
#define num second typedef long long LL;
typedef unsigned long long ULL;
typedef vector<long long> VLL;
typedef vector<int> VI; LL gcd(LL a, LL b) {
return b ? gcd(b, a % b) : a;
} const int N = 2e5 + 10;
LL b[N];
int n;
PII a[N]; bool check(int x) {
LL t = b[x];
for (int i = x + 1; i <= n; i++) {
if (t >= a[i].score) {
t += (LL) a[i].score;
continue;
}
else return false;
}
return true;
} void solve() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i].score);
a[i].second = i;
}
sort(a + 1, a + n + 1); for (int i = 1; i <= n; i++) b[i] = b[i - 1] + (LL) a[i].score;
int l = 1, r = n;
while (l < r) {
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
vector<int> res;
for (int i = l; i <= n; i++) res.push_back(a[i].num);
sort(res.begin(), res.end()); printf("%d\n", n - l + 1);
for (auto &it : res) printf("%d ", it);
puts("");
} int main()
{
//ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int t;
scanf("%d", &t);
while (t--) {
solve();
} return 0;
}

F. Equalize the Array

链接:F题链接

题目大意:

设\(cnt_x\)为数组中每个数的出现次数,如果一个数组中的数只有\(C\)次或者\(0\)次可以认为这个数组是漂亮的,所以我们现在要做的就是删掉某些数使得这个数组是漂亮的。

思路

按照题意,\(cnt_x\)小于\(C\)的\(x\)那么全部删除,大于\(C\)的需要删除\(cnt_x - C\)个,所以有:

\[删除个数 = \sum\limits_{cnt_x < C} cnt_x + \sum\limits_{cnt_x >= C} (cnt_x - C)
\]

看到这个公式能想到什么,当然是前缀和。

但是有一个问题,\(C\)的范围一定是某个数的出现次数吗,如果不是,那么就没法用前缀和做了,那怎么证明呢,如果\(C\)不是某个数的出现次数,我们令某个刚好大于\(C\)的次数为\(Y\),可以发现,\(\sum\limits_{cnt_x < C} cnt_x\)没有发生变化,而大于\(\sum\limits_{cnt_x >= C} (cnt_x - C) > \sum\limits_{cnt_x >= Y} (cnt_x - Y)\),这样于是删除个数变大了,所以我们根本不需要考虑如果\(C\)不是某个数的出现次数这种情况。

有了前缀和\(presum\),根据公式,左边就有\(left = presum[i - 1]\), 右边就有\(right = (presum[last] - presum[i - 1]) - (last - i + 1) * cnt[i]\),于是更新答案即可。

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <map>
#include <cstring> using namespace std; #define Inf 0x3f3f3f3f
#define PII pair<int, int>
#define P2LL pair<long long, long long>
#define endl '\n' typedef long long LL;
typedef unsigned long long ULL;
typedef vector<long long> VLL;
typedef vector<int> VI; LL gcd(LL a, LL b) {
return b ? gcd(b, a % b) : a;
} const int N = 2e5 + 10;
int n, c;
LL presum[N]; bool cmp(int a, int b) {
return a > b;
} void solve() {
scanf("%d", &n);
map<LL, LL> mp;
for (int i = 0; i < n; i++) {
scanf("%d", &c);
mp[c]++;
} vector<LL> cnt; //计数 数字出现的次数
for (auto &it : mp) cnt.push_back(it.second);
cnt.push_back(0);
sort(cnt.begin(), cnt.end()); LL res = n;
int last = cnt.size() - 1;
for (int i = 1; i < cnt.size(); i++) presum[i] = presum[i - 1] + cnt[i];
for (int i = 1; i <= last; i++) {
LL left = presum[i - 1], right = (presum[last] - presum[i - 1]) - (last - i + 1) * cnt[i];
res = min(res, left + right);
}
printf("%d\n", res);
} int main()
{
//ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int t;
scanf("%d", &t);
while (t--) {
solve();
} return 0;
}

G - Old Floppy Drive

链接:G题链接

题目大意:

现在有个含有\(n\)个元素的数组\(a\),且有一个指针指向\(a\)的初始,还有一个\(m\)个元素的数组\(x\),对于每一个\(x_i\),指针会不停的运动,如果数组末尾那么它会重新指会第一个元素继续运动,直到指针走过的数组所有元素的和\(≥x\),那么指针停止,求指针的运动次数。

思路

设数组总和为\(S\),前缀和为\(preSum\),运行一次的时间是\(T\),那么运行\(t\)秒,那么走过的总和\(Sum\):

\[Sum = \lfloor \cfrac{t}{T} \rfloor * S + preSum \, [t \, mod \, T]
\]

由此可见,如果\(S \leq 0\) 并且 \(\max\limits_{i = 1}^n \, preSum[i] < x\)那么指针将永远运行下去不会停止,那么直接输出\(-1\)即可。

然后就分别求磁盘转动的整圈数,然后再加上\(\max\limits_{i = 1}^n \, preSum[i] \geq x\)的最小位置\(i\),可以知道,对于磁盘的转动整圈数不得少于\(\lceil \frac{x - \max\limits_{i = 1}^n \, preSum[i] \, }{S} \rceil\),少于转不到,多于的话也就不能保证答案是最小位置了。

最后就需要找到\(\max\limits_{i = 1}^n \, preSum[i] \geq x\)的位置\(i\)了,可以用二分,注意这个前缀和并不是随随便便的前缀和,处理它的时候保证它是单调递增的且\(>0\),如果小于等于\(0\)那么对总和\(Sum\)没有任何贡献,并且单调递增才能保证我们可以得到那个刚好\(\max\limits_{i = 1}^n \, preSum[i] \geq x\)的位置\(i\),而这一步我们可以用二分lower_bound寻找即可。

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <map>
#include <cstring> using namespace std; #define Inf 0x3f3f3f3f
#define PII pair<int, int>
#define P2LL pair<long long, long long>
#define endl '\n' typedef long long LL;
typedef unsigned long long ULL;
typedef vector<long long> VLL;
typedef vector<int> VI; LL gcd(LL a, LL b) {
return b ? gcd(b, a % b) : a;
} const int N = 2e5 + 10;
int n, m;
LL presum[N];
LL preInd[N]; //记录前缀的坐标 void solve() {
int idx = 0; //当前坐标
LL allsum = 0, c;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%lld", &c);
allsum += c;
if (allsum > presum[idx]) {
presum[++idx] = allsum;
preInd[idx] = i;
}
} for (int i = 1; i <= m; i++) {
LL x;
scanf("%lld", &x);
if (presum[idx] < x && allsum <= 0) {
printf("%d ", -1);
continue;
}
LL needspins = 0;
if (presum[idx] < x) {
needspins = (x - presum[idx] + allsum - 1) / allsum;
}
x -= needspins * allsum;
LL q = lower_bound(presum + 1, presum + idx + 1, x) - presum;
LL res = needspins * n + preInd[q] - 1; //因为前缀从1开始,那么减去1
printf("%lld ", res);
}
puts("");
} int main()
{
//ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int t;
scanf("%d", &t);
while (t--) {
solve();
} return 0;
}

Codeforces Round #702 (Div. 3) 题解的更多相关文章

  1. Codeforces Round #182 (Div. 1)题解【ABCD】

    Codeforces Round #182 (Div. 1)题解 A题:Yaroslav and Sequence1 题意: 给你\(2*n+1\)个元素,你每次可以进行无数种操作,每次操作必须选择其 ...

  2. Codeforces Round #608 (Div. 2) 题解

    目录 Codeforces Round #608 (Div. 2) 题解 前言 A. Suits 题意 做法 程序 B. Blocks 题意 做法 程序 C. Shawarma Tent 题意 做法 ...

  3. Codeforces Round #525 (Div. 2)题解

    Codeforces Round #525 (Div. 2)题解 题解 CF1088A [Ehab and another construction problem] 依据题意枚举即可 # inclu ...

  4. Codeforces Round #528 (Div. 2)题解

    Codeforces Round #528 (Div. 2)题解 A. Right-Left Cipher 很明显这道题按题意逆序解码即可 Code: # include <bits/stdc+ ...

  5. Codeforces Round #466 (Div. 2) 题解940A 940B 940C 940D 940E 940F

    Codeforces Round #466 (Div. 2) 题解 A.Points on the line 题目大意: 给你一个数列,定义数列的权值为最大值减去最小值,问最少删除几个数,使得数列的权 ...

  6. Codeforces Round #677 (Div. 3) 题解

    Codeforces Round #677 (Div. 3) 题解 A. Boring Apartments 题目 题解 简单签到题,直接数,小于这个数的\(+10\). 代码 #include &l ...

  7. Codeforces Round #665 (Div. 2) 题解

    Codeforces Round #665 (Div. 2) 题解 写得有点晚了,估计都官方题解看完切掉了,没人看我的了qaq. 目录 Codeforces Round #665 (Div. 2) 题 ...

  8. Codeforces Round #160 (Div. 1) 题解【ABCD】

    Codeforces Round #160 (Div. 1) A - Maxim and Discounts 题意 给你n个折扣,m个物品,每个折扣都可以使用无限次,每次你使用第i个折扣的时候,你必须 ...

  9. Codeforces Round #383 (Div. 2) 题解【ABCDE】

    Codeforces Round #383 (Div. 2) A. Arpa's hard exam and Mehrdad's naive cheat 题意 求1378^n mod 10 题解 直接 ...

  10. Codeforces Round #271 (Div. 2)题解【ABCDEF】

    Codeforces Round #271 (Div. 2) A - Keyboard 题意 给你一个字符串,问你这个字符串在键盘的位置往左边挪一位,或者往右边挪一位字符,这个字符串是什么样子 题解 ...

随机推荐

  1. opencv-python中 boundingRect(cnt)以及cv2.rectangle用法

    矩形边框(Bounding Rectangle)是说,用一个最小的矩形,把找到的形状包起来.还有一个带旋转的矩形,面积会更小,效果见下图 首先介绍下cv2.boundingRect(img)这个函数 ...

  2. Proxmox VE软件防火墙的配置

    1 软件防火墙的基本概念 防火墙是计算机网络中用于保护网络安全的关键技术.防火墙可以是硬件设备部署在网络出口,也可以是软件部署在终端设备出口.本文主要介绍软件防火墙. 软件防火墙可以根据网络流量的方向 ...

  3. CSSRelated

    CSS 几种常用的清除浮动方法 ️️️ 父级 div 定义伪类:after 和 zoom; /* 这个class名指的是需要清除浮动的父级 */ .clearfloat:after { display ...

  4. 带你走进数仓大集群内幕丨详解关于作业hang及残留问题定位

    本文分享自华为云社区<[带你走进DWS大集群内幕]大集群通信:作业hang.残留问题定位>,作者: 雨落天穹丶. 前言: 测试过程中,我们会遇到这样一种情况,我的作业都执行很久了,为啥还不 ...

  5. javascript创建数组

    javascript数组:var array=[ ]等于创建一个数组 array[0]代表给数组的第一个位置上赋值,值为32 array[5]代表给数组的第六位置上赋值.值为3 在位置0,1,2,5位 ...

  6. CodeForces 1343E Weights Distributing

    题意 多组样例 给定\(n,m,a,b,c\),给定一个长度为\(m\)的数组\(p[]\),给定\(m\)条边,构成一个\(n\)个点\(m\)条边的无向图,\(Mike\)想要从\(a\)走到\( ...

  7. FastDFS入门

    一.系统架构 二.构成部分 1.Tracker Server:跟踪服务器,记录文件信息,可单台或集群部署. 2.Storage Server:存储服务器,文件存储位置,分卷或分组部署. 3.Clien ...

  8. Python基础语法--课程笔记

    Smiling & Weeping ----我的心是旷野的鸟,在你的眼睛里找到了它的天空 定义和使用类: 1.声明类: class类名: 成员变量,成员函数 2.定义类的对象: 对象名 = 类 ...

  9. ps--提升字体排版的美感四个有效方法

    一,文字的摆放位置 (字体的选择不要超过三种,分散注意力)

  10. Cplex求解教程(基于OPL语言,可作为大规模运算输入参考)

    最近导导让牛牛改篇论文,牛牛在她的指导下把非线性问题化成了线性.然鹅,化成线性后的模型决策变量和约束条件均达到上百甚至上千个,这让牛牛犯了难,以下方法或许能为这样大规模模型的变量和约束输入提供思路(๑ ...