Codeforces Round #702 (Div. 3) A~F题解
A. Dense Array
- 解题思路
我们将这个公式变化一下,实际上就是要求相邻两个数 a i , a i + 1 a_i,a_{i+1} ai,ai+1满足 a i ≤ 2 a i + 1 a_i\leq 2a_{i+1} ai≤2ai+1或者 a i + 1 ≤ 2 a i a_{i+1}\leq 2a_{i} ai+1≤2ai,所以我们贪心维护这样的条件即可。 - AC代码
/**
*@filename:A
*@author: pursuit
*@csdn:unique_pursuit
*@email: 2825841950@qq.com
*@created: 2021-06-07 08:48
**/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 50 + 5;
const int P = 1e9+7;
int t,n,a[N];
void solve(){
int cnt = 0;
for(int i = 2; i <= n; ++ i){
int temp1 = max(a[i],a[i - 1]) ,temp2 = (min(a[i],a[i - 1]) * 2);
//维护。
while(temp1 > temp2){
cnt ++;
temp1 = (temp1 + 1) / 2;
}
}
cout << cnt << endl;
}
int main(){
cin >> t;
while(t -- ){
cin >> n;
for(int i = 1; i <= n; ++ i){
cin >> a[i];
}
solve();
}
return 0;
}
B. Balanced Remainders
- 解题思路
首先我们需要知道,我们只在意每个数对 3 3 3的余数,所以我们可以分成 0 , 1 , 2 0,1,2 0,1,2三组,而这三组的数量一定要平均,即都为平均值。 一步移动只能从 0 − > 1 , 1 − > 2 , 2 − > 0 0- >1,1->2,2->0 0−>1,1−>2,2−>0,那么根据贪心思想,首先我们处理多出来的部分,遍历将多出来的进行一步移动,由于这次遍历已经处理好了一些情况,所以我们只需统计每组与平均值的差值即可。 - AC代码
/**
*@filename:B
*@author: pursuit
*@csdn:unique_pursuit
*@email: 2825841950@qq.com
*@created: 2021-06-07 08:49
**/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100000 + 5;
const int P = 1e9+7;
int t,n,a[N],c[3];
void solve(){
//从0 - > 1转换1次,从1 - > 2转换1次,从2 - > 0转换一次。
int avg = (c[0] + c[1] + c[2]) / 3;
int cnt = 0;
for(int i = 0; i < 3; ++ i){
if(c[i] > avg){
c[(i + 1) % 3] += (c[i] - avg);
cnt += c[i] - avg;
}
}
for(int i = 0; i < 3; ++ i){
if(c[i] < avg){
cnt += avg - c[i];
}
}
cout << cnt << endl;
}
int main(){
scanf("%d", &t);
while(t -- ){
scanf("%d", &n);
memset(c,0,sizeof(c));
for(int i = 1; i <= n; ++ i){
scanf("%d", &a[i]);
c[a[i] % 3] ++ ;
}
solve();
}
return 0;
}
C. Sum of Cubes
-
解题思路
这道题比较好理解,就是对于 a 3 + b 3 = x 3 a^3+b^3=x^3 a3+b3=x3,已知 x x x,判断是否存在这样的 a , b a,b a,b。我们有两种做法,一种是预处理出所有的立方和, x x x最大为 1 0 12 10^{12} 1012,所以我们只需要处理 1 0 4 10^4 104的数量级,这种很方便。当然我们这里采用的是枚举 a a a,然后二分判断是否存在这样的 b b b即可。效率也很高。 -
AC代码
/**
*@filename:C
*@author: pursuit
*@csdn:unique_pursuit
*@email: 2825841950@qq.com
*@created: 2021-06-07 08:49
**/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100000 + 5;
const int P = 1e9+7;
int t;
ll x;
bool pow(ll x){
ll l = 1,r = sqrt(x);
while(l < r){
ll mid = (l + r) >> 1;
ll temp = mid * mid * mid;
if(temp > x){
r = mid - 1;
}
else if(temp == x){
return true;
}
else{
l = mid + 1;
}
}
if(l * l * l == x || r * r * r == x)return true;
return false;
}
void solve(){
for(ll i = 1;; ++ i){
if(i * i * i >= x)break;
ll j = x - i * i * i;
if(pow(j)){
puts("YES");
return;
}
}
puts("NO");
}
int main(){
cin >> t;
while(t -- ){
cin >> x;
solve();
}
return 0;
}
D. Permutation Transformation
-
解题思路
这道题还是比较简单的, 我们先找到树根,再构造左右子树,而找树根即是找所处区间中的最大值。 -
AC代码
/**
*@filename:D
*@author: pursuit
*@csdn:unique_pursuit
*@email: 2825841950@qq.com
*@created: 2021-06-07 08:49
**/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100 + 5;
const int P = 1e9+7;
int t,n,a[N];
int root[N];
void dfs(int l,int r,int step){
int maxx = 0,idx = 0;
for(int i = l; i <= r; ++ i){
if(a[i] > maxx){
maxx = a[i];
idx = i;
}
}
if(idx != 0){
root[idx] = step;
dfs(l,idx - 1,step + 1);
dfs(idx + 1,r,step + 1);
}
}
void solve(){
//先找到树根。
for(int i = 1; i <= n; ++ i){
if(a[i] == n){
root[i] = 0;
dfs(1,i - 1,1);
dfs(i + 1,n,1);
break;
}
}
for(int i = 1; i <= n; ++ i){
cout << root[i] << " ";
}
cout << endl;
}
int main(){
cin >> t;
while(t -- ){
cin >> n;
for(int i = 1; i <= n; ++ i){
cin >> a[i];
}
solve();
}
return 0;
}
E. Accidental Victory
-
解题思路
我们可以对他们的值进行排序。 那么我们如果找到了第一个获胜的人,根据后效性(因为后面的一定能获胜这个人,所以他们也一定有可能是冠军)。 而找到第一个获胜的人,我们则可二分查找,需要注意的是,我们需要及时判断及时更新当前的值。 -
AC代码
/**
*@filename:E
*@author: pursuit
*@csdn:unique_pursuit
*@email: 2825841950@qq.com
*@created: 2021-06-07 12:30
**/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 200000 + 5;
const int P = 1e9+7;
int t,n;
pii a[N];
ll sum[N];
bool check(int mid){
ll temp = sum[mid];
for(int i = mid + 1; i <= n; ++ i){
if(a[i].first > temp)return false;
temp += a[i].first;
}
return true;
}
void solve(){
//贪心获取,最小值一定不可以。利用最小值的前缀和。由于具有后效性,所以我们直接找到第一个获胜的人即可。
sort(a + 1,a + 1 + n);
for(int i = 1; i <= n; ++ i){
sum[i] = sum[i - 1] + a[i].first;
}
int l = 1,r = n;
while(l < r){
int mid = (l + r) >> 1;
if(check(mid)){
r = mid;
}
else{
l = mid + 1;
}
}
cout << n - l + 1 << endl;
vector<int> pos;
for(int i = l; i <= n; ++ i){
pos.push_back(a[i].second);
}
sort(pos.begin(),pos.end());
for(auto & x : pos){
cout << x << ' ';
}
cout << endl;
}
int main(){
scanf("%d", &t);
while(t -- ){
scanf("%d", &n);
for(int i = 1; i <= n; ++ i){
scanf("%d", &a[i].first);
a[i].second = i;
}
solve();
}
return 0;
}
F. Equalize the Array
- 解题思路
由于数据范围达到 1 e 9 1e9 1e9,且我们并不在意每个数的值,所以我们需要进行离散化存储它们出现的次数,最后对出现次数进行排序且求前缀和便于之后枚举处理。 枚举我们需要删除的数,那么次数少于它的就必须全部清除,次数大于它的就必须降到和它一样,由于已经排过序了,所以我们可以直接利用前缀和处理。 - AC代码
/**
*@filename:F
*@author: pursuit
*@csdn:unique_pursuit
*@email: 2825841950@qq.com
*@created: 2021-06-07 13:16
**/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 200000 + 5;
const int P = 1e9+7;
int t,n,a[N],cnt[N];
int sum[N];
void solve(){
int tot = 1;
sort(a + 1,a + 1 + n);
int pre = -1;
for(int i = 1; i <= n; ++ i){
if(pre == -1)pre = a[i];
if(a[i] == pre){
cnt[tot] ++;
}
else{
tot ++;
pre = a[i];
cnt[tot] ++;
}
}
sort(cnt + 1,cnt + tot + 1);
for(int i = 1; i <= tot; ++ i){
sum[i] = sum[i - 1] + cnt[i];
//cout << cnt[i] << " ";
}
//cout << endl;
int minn = 0x3f3f3f3f;
for(int i = 1; i <= tot; ++ i){
minn = min(minn,sum[i - 1] + (sum[tot] - sum[i]) - (tot - i) * cnt[i]);
}
printf("%d\n",minn);
}
int main(){
scanf("%d", &t);
while(t -- ){
scanf("%d", &n);
memset(cnt,0,sizeof(cnt));
for(int i = 1; i <= n; ++ i){
scanf("%d", &a[i]);
}
solve();
}
return 0;
}

浙公网安备 33010602011771号