Codeforces Round #760 (Div. 3) A-E题解

Codeforces Round #760 (Div. 3)

本场div3还是延续老传统,全部思维题(但是G题还没开,未知,明天待补题),A-F全思维题,并没用到算法和数据结构。

A. Polycarp and Sums of Subsequences

水题,已知有三个数字x,y,z;告诉x,y,z,x+y,x+z,y+z,x+y+z这七个数,但是不知道谁是谁,让分离出x,y,z。

很容易知道最小的两个数一定是x,y,z中的两个小数,最大的肯定是x+y+z,这样就分离出来了。

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
typedef long long ll;
ll a[N];

int main() {
    int t;
    cin >> t;
    while (t--) {
        for (int i = 1; i <= 7; i++)
            cin >> a[i];
        sort(a + 1, a + 8);
        ll x = a[1], y = a[2], sum = a[7];
        cout << x << " " << y << " " << sum - x - y << endl;
    }
    return 0;
}

B. Missing Bigram

一个由a和b组成的n位字符串,两两按顺序排列有n-1组,输入n-2组(有一组未知),需要找出原来的n位字符串。

只要找两个相邻字符串,前一个的后一位和后一个的前一位如果不一致,就插入那个未知的在该位置;如果都一致,就可能遗失了相同字符组成的,没有影响其他组,直接把最后一个字符输出两遍即可。

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
typedef long long ll;
ll a[N];
string str[N];

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        for (int i = 1; i <= n - 2; i++)
            cin >> str[i];
        int flag = 0;
        for (int i = 2; i <= n - 2; i++) {
            if (str[i][0] != str[i - 1][1]) {
                flag = i - 1;
                str[n - 1] = "";
                str[n - 1] += str[i - 1][1];
                str[n - 1] += str[i][0];
            }
        }
        if (flag == 0) {
            for (int i = 1; i <= n - 2; i++) {
                cout << str[i][0];
            }
            cout << str[n - 2][1] << str[n - 2][1] << endl;
        } else {
            for (int i = 1; i <= n - 2; i++) {
                cout << str[i][0];
                if (flag == i) {
                    cout << str[i][1];
                }
            }
            cout << str[n - 2][1] << endl;
        }
    }
    return 0;
}

C. Paint the Array

给定一个长度为n的数组,问能否找到一个d,使得奇数位和偶数位两种位置上,满足其中一种全部整除d,另一组全部无法整除d?

首先先分离成两个数组,当然可以不分离,就是枚举奇偶位。然后分别去求整体的gcd。分成两种情况,当两个gcd相等时,这意味着不可能存在d,直接输出0。这是因为如果存在d<=gcd,那么奇偶位均可以整除,如果存在d>gcd,一定奇偶位都不能整除。当两个gcd不等时,需要分别试探采用其中一个gcd,另一个数组是否可以成立(即没有数能够整除),哪个成立输出哪个,没有成立的就输出0。

容易错的思路是:解题者会不由自主地用大的gcd,而忽略了另一个较小的gcd,事实上两个都有可能成为d,都需要试探一下。此外,本题数据范围会爆int,要开ll。

#include <bits/stdc++.h>
#define F first
#define S second
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;

ll a[N], b[N], c[N];

ll gcd(ll x, ll y) {
    if (x < y) {
        ll tem = x;
        x = y;
        y = tem;
    }
    if (x % y == 0)
        return y;
    else
        return gcd(y, x % y);
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        int cnt = 0, cnt2 = 0;
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
            if (i % 2)
                b[++cnt] = a[i];
            else
                c[++cnt2] = a[i];
        }
        ll x1 = b[1], x2 = c[1];
        for (int i = 1; i <= cnt; i++) {
            x1 = gcd(x1, b[i]);
        }
        for (int i = 1; i <= cnt2; i++) {
            x2 = gcd(x2, c[i]);
        }
        // cout << x1 << " " << x2 << endl;
        if (x1 != x2) {
            int flag1 = 1, flag2 = 1;
            for (int i = 1; i <= cnt; i++) {
                if (b[i] % x2 == 0) {
                    flag1 = 0;
                    break;
                }
            }
            for (int i = 1; i <= cnt2; i++) {
                if (c[i] % x1 == 0) {
                    flag2 = 0;
                    break;
                }
            }
            if (flag1)
                cout << x2 << endl;
            else if (flag2)
                cout << x1 << endl;
            else
                cout << 0 << endl;
        } else {
            cout << 0 << endl;
        }
    }
    return 0;
}

D. Array and Operations

在这里插入图片描述题目不太好译,直接截图放上来了。

本题其实是一个彻底的贪心,最初想过用dfs爆搜,但是必然会t。我最初的思路是计算贡献值
b o n u s [ x ] [ y ] = x + y − f l o o r ( x / y ) bonus[x][y]=x+y-floor(x/y) bonus[x][y]=x+yfloor(x/y)
用一个二维数组存起来,每次弹出一个最大值,把x和y置为已用状态。但是过不了样例,第一组数据很明显是1和2、1和3分组,而不是2和3分组。

正解是先排序,先最大化需要被消灭的数(最大的前k个数),剩下的数直接计入score,然后再最小化前k个数里的商和。这里依然有几个方案,一个是首尾配对,一个是相邻配对,一个是等距配对。这里采用第三种方法,确保分到同一组里的两个数尽可能有差距。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x7fffffff;
const int N = 105;
ll a[N];

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n, k;
        int score = 0;
        cin >> n >> k;
        for (int i = 1; i <= n; i++)
            cin >> a[i];
        sort(a + 1, a + n + 1);
        for (int i = 1; i <= n - 2 * k; i++) {
            score += a[i];
        }
        for (int i = 1; i <= k; i++) {
            score += (a[n - 2 * k + i] / a[n - k + i]);
        }
        cout << score << endl;
    }
    return 0;
}

E. Singers’ Tour

在这里插入图片描述

以6个音乐家为例,循环之后可以得到下面这个方程组,常规思路是求解线性方程组,但是可以发现各式加起来可以求得a1+···+a6的值,经过若干次等式加减可以直接得到a1–a6的式子。
b 1 = a 1 + 6 a 2 + 5 a 3 + 4 a 4 + 3 a 5 + 2 a 6 b 2 = 2 a 1 + a 2 + 6 a 3 + 5 a 4 + 4 a 5 + 3 a 6 b 3 = 3 a 1 + 2 a 2 + a 3 + 6 a 4 + 5 a 5 + 4 a 6 b 4 = 4 a 1 + 3 a 2 + 2 a 3 + a 4 + 6 a 5 + 5 a 6 b 5 = 5 a 1 + 4 a 2 + 3 a 3 + 2 a 4 + a 5 + 6 a 6 b 6 = 6 a 1 + 5 a 2 + 4 a 3 + 3 a 4 + 2 a 5 + a 6 b_1=a_1+6a_2+5a_3+4a_4+3a_5+2a_6\\ b_2=2a_1+a_2+6a_3+5a_4+4a_5+3a_6\\ b_3=3a_1+2a_2+a_3+6a_4+5a_5+4a_6\\ b_4=4a_1+3a_2+2a_3+a_4+6a_5+5a_6\\ b_5=5a_1+4a_2+3a_3+2a_4+a_5+6a_6\\ b_6=6a_1+5a_2+4a_3+3a_4+2a_5+a_6 b1=a1+6a2+5a3+4a4+3a5+2a6b2=2a1+a2+6a3+5a4+4a5+3a6b3=3a1+2a2+a3+6a4+5a5+4a6b4=4a1+3a2+2a3+a4+6a5+5a6b5=5a1+4a2+3a3+2a4+a5+6a6b6=6a1+5a2+4a3+3a4+2a5+a6
需要特判不成立的情况,第一种是b的和不能整除(n+1)* n/2,正对应了把上面式子加起来除以(n+1)*n/2得到a1+···+an;第二种是在运算过程中发现ai的值为0或为负,或除不尽,都要输出NO。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 4e4 + 5;
ll a[N], b[N];

int main() {
    int t;
    cin >> t;
    while (t--) {
        ll n;
        ll sum = 0;
        cin >> n;
        for (int i = 1; i <= n; i++) {
            cin >> b[i];
            sum += b[i];
        }
        if (sum % (n * (n + 1) / 2) != 0) {
            cout << "NO" << endl;
            continue;
        }
        sum /= (n * (n + 1) / 2);
        b[n + 1] = b[1];
        int flag = 1;
        for (int i = 2; i <= n + 1; i++) {
            a[i] = (sum - (b[i] - b[i - 1])) / n;
            if (a[i] <= 0 || (sum - (b[i] - b[i - 1])) % n != 0) {
                flag = 0;
                break;
            }
        }
        if (!flag) {
            cout << "NO" << endl;
            continue;
        }
        cout << "YES" << endl;
        for (int i = 1; i <= n; i++) {
            if (i == 1)
                cout << a[n + 1] << " ";
            else
                cout << a[i] << " ";
        }
        cout << endl;
    }
    return 0;
}

F. Reverse

待补题

G. Trader Problem

待补题

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值