AtCoder Regular Contest 128

Posted Yeyuqing0913

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AtCoder Regular Contest 128相关的知识,希望对你有一定的参考价值。

A - Gold and Silver

题意:一开始,手头上只有一个黄金,有n天,每天一个黄金可以交换\\(a_i\\)个白银,并且\\(a_i\\)个白银也可以交换1个黄金,问每一天最多可以得到多少黄金,(每天如果换的话,就要全部换掉)

sol.发现,一定是 开始选一个大的,再选一个小的这样

B - Balls of Three Colors

题意:\\(给你R,G,B(R ,G,B<= 1e8)\\),数量的三种颜色不同的小球,问你所需执行的最小次数操作(操作类似于 用一个红球,一个蓝球,换2两个绿球)

sol.

C - Max Dot

题意:给你\\(n,m,S\\),以及一个序列\\(\\{a_i\\}\\),构造一个序列\\(\\{x_i\\}\\),使得

\\[0<= x_1<=x_2<=...<= x_n <= M\\\\ \\sum_{i = 1}^nx_i = S\\\\ 最大化 \\sum_{i = 1} ^ n x_i * a_i \\]

AtCoder Regular Contest 098

传送门

C - Attention

前后缀搞一搞即可。


Code

#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
//#define Local
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 3e5 + 5;

int n;
char s[N];
int pre[N], suf[N];

void run() {
    cin >> s + 1;
    for(int i = 1; i <= n; i++) {
        pre[i] = pre[i - 1];
        if(s[i] == 'W') ++pre[i];
    }
    suf[n + 1] = 0;
    for(int i = n; i >= 1; i--) {
        suf[i] = suf[i + 1];
        if(s[i] == 'E') ++suf[i];
    }
    int ans = n + 1;
    for(int i = 1; i <= n; i++) {
        ans = min(ans, pre[i - 1] + suf[i + 1]);
    }
    cout << ans << '
';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
#ifdef Local
    freopen("../input.in", "r", stdin);
    freopen("../output.out", "w", stdout);
#endif
    while(cin >> n) run();
    return 0;
}

D - Xor Sum 2

题意:
给出一个长度为(n)的序列(a),现在问有多少区间([l,r]),满足:
[ a_l xor a_{l+1} xor cdots xor x_r=a_l+a_{l+1}+cdots+a_r ]

思路:
注意这样一个性质:(a_i xor a_jleq a_i+a_j)
所以一旦一个区间不满足条件过后,更大的区间也不满足了;一个区间满足条件,更小的区间也满足。
所以直接双指针搞搞就行。


Code

#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
//#define Local
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 2e5 + 5;

int n;
int a[N];

void run() {
    for(int i = 1; i <= n; i++) cin >> a[i];
    int j = 0;
    ll sum1 = 0, sum2 = 0;
    ll ans = 0;
    for(int i = 1; i <= n; i++) {
        while(j + 1 <= n) {
            if(sum1 + a[j + 1] == (sum2 ^ a[j + 1])) {
                sum1 += a[++j], sum2 ^= a[j];
            }
            else break;
        }
        ans += j - i + 1;
        sum1 -= a[i]; sum2 ^= a[i];
    }
    cout << ans << '
';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
#ifdef Local
    freopen("../input.in", "r", stdin);
    freopen("../output.out", "w", stdout);
#endif
    while(cin >> n) run();
    return 0;
}

E - Range Minimum Queries

题意:
给出一个长度为(n)的序列(a),现在执行(q)次操作,每次选择一段长度为(k)的区间,删除一个最小的数(如果有多个,可任意删除一个)。
最后问在所有删除的数中,相差最小为多少。

思路:

  • 很容易想到二分差值,然后枚举下界,这样就知道了上下界。
  • 因为每次必须选择最小的一个数,所以所有大于等于下界的数构成了一个个可执行区间(因为若区间中含小于的数那肯定不合法),每次在这些区间里面贪心选就行。

详见代码:


Code

#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
//#define Local
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 2005;

int n, k, q;
int a[N];

bool chk(int x) {
    for(int i = 1; i <= n; i++) {
        int Min = a[i];
        int res = 0;
        for(int l = 1, r; l <= n; l = r) {
            r = l;
            if(a[l] < Min) {
                ++r; continue;
            }
            int cnt = 0;
            while(r <= n && a[r] >= Min) {
                if(a[r] <= Min + x) ++cnt;
                ++r;
            }
            if(r - l >= k) res += min(r - l + 1 - k, cnt);
        }
        if(res >= q) return true;
    }
    return false;
}

void run() {
    for(int i = 1; i <= n; i++) cin >> a[i];
    int l = 0, r = 1e9 + 1, mid;
    while(l < r) {
        mid = (l + r) >> 1;
        if(chk(mid)) r = mid;
        else l = mid + 1;
    }
    cout << l << '
';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
#ifdef Local
    freopen("../input.in", "r", stdin);
    freopen("../output.out", "w", stdout);
#endif
    while(cin >> n >> k >> q) run();
    return 0;
}

F - Donation

题意:
给出一个无向图,选定一个起点,一开始有(W)元,之后可以选择走向相邻一个节点或者给当前结点捐赠(b_i)元,若走向一个结点至少得有(a_i)元才行。
现在确定一个最小的(W)以及一个起点,使得最终能够顺利捐赠成功每个点。

思路:
还有点没想清楚,先埋个坑。

以上是关于AtCoder Regular Contest 128的主要内容,如果未能解决你的问题,请参考以下文章

刷题AtCoder Regular Contest 001

AtCoder Regular Contest 094

[Atcoder Regular Contest 060] Tutorial

AtCoder Regular Contest 103

AtCoder Regular Contest 128

AtCoder Regular Contest 119 C