Educational Codeforces Round 93 (Rated for Div. 2)

比赛链接

A. Bad Triangle

题意:

给一组非降序列\(a\),问这组序列是否存在三个数使得这三个数无法构成三角形。

思路:

因为序列是排好序的,根据三角形任意两边之和大于第三边,判断第\(1,2,n\)条边能否构成三角形就好了。

代码:

#include <cstdio>
#include <algorithm>
#include <cstring>
#define INF 1000000005
typedef long long ll;

const int maxn = 50005;
using namespace std;

int a[maxn], T, n;

int main() {
    scanf("%d", &T);
    while (T--) {
        scanf("%d", &n);
        for (int i = 0; i < n; i++)
            scanf("%d", a + i);
        if (a[0] + a[1] <= a[n - 1]) {
            printf("1 2 %d\n", n);
        }
        else if (a[n - 1] - a[0] >= a[1]) {
            printf("1 2 %d\n", n);
        }
        else {
            printf("-1\n");
        }
    }
    return 0;
}

B. Substring Removal Game

题意:

给定一组\(01\)串,每次可以选择一段连续的\(0\)串或者\(1\)串。\(Alice\)\(Bob\)在进行这场游戏,\(Alice\)先手。每个人都有分数,分数等于这个人选过所有数字的和。\(Alice\)\(Bob\)都希望自己的分数尽可能高。问\(Alice\)的分数最高是多少?

思路:

两个玩家每次都一定选择最长的一串\(1\)。因为如果有一个玩家选择了一串\(0\),那么另一个玩家就能一次选择更多的\(1\),犯不着给对手方便。如果一个玩家一次只选择一串\(1\)的一段,那么这一段剩下的\(1\)就有可能在将来归对手所有,不如一次直接全选。

代码:

#include <cstdio>
#include <cstring>
#include <map>
#include <queue>

const int maxn = 128;

using namespace std;

char s[maxn];
int n, T, cur, cnt, ans;
priority_queue<int> q;

inline void init() {
    cur = 0;
    ans = 0;
    cnt = 0;
    while (!q.empty()) q.pop();
}

int main() {
    scanf("%d", &T);
    while (T--) {
        init();
        scanf("%s", s);
        n = strlen(s);

        while (cur < n) {
            while (s[cur] == '0' && cur < n) cur++;
            cnt = 0;
            while (s[cur] == '1' && cur < n) {
                cnt++;
                cur++;
            }
            q.push(cnt);
        }

        bool flag = false;
        while (!q.empty()) {
            int u = q.top();
            q.pop();

            if (!flag)
                ans += u;
            flag = !flag;
        }

        printf("%d\n", ans);
    }
    return 0;
}

C. Good Subarrays

比赛的时候没想出来,所以是补题的时候补的。(其实比赛的时候想得差不多了QAQ,没特别考虑\(sum_i - i = 0\)的情况,所以代码不对QAQ)

题意:

给定\(n\)和一串\(n\)个数字,如果存在一段连续的\(\sum\limits_{i=l}^{r}a_i=r - l + 1\),那么我们称这一段子串为good subarray。问一共有多少good subarrays。

思路:

先做一遍前缀和,得到所有的\(sum_i\)。这样,我们要求的就变成了\(sum_r - sum_{l - 1} = r - l + 1\)

移项,得\(sum_r - r = sum_{l-1} - (l - 1)\)

所以,我们求出所有的\(sum_i - i\),然后\(ans = ans + num_{sum_i - i}, num_{sum_i - i} = num_{sum_i - i} + 1\)

其中,\(num_{sum_i - i}\)是之前\(sum_i - i\)出现的次数。

这里要特别注意一下\(sum_i - i = 0\)的情况,是因为,\(sum_i - i = 0\)第一次出现的时候,从\(1\)\(i\)求和本身就是一个good subarray。所以要把\(num_0\)初始化为\(1\)

代码:

代码中的\(sum\)是直接利用\(a\)数组存的。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
typedef long long ll;

using namespace std;
const int maxn = 100005;

int T, n;
ll a[maxn];
ll ans = 0;
map<ll, ll> p;

inline void read(ll *a) {
    int len = 0;
    char ch = getchar();
    while (ch < '0' || ch > '9') ch = getchar();
    while (ch >= '0' && ch <= '9') {
        a[++len] = ch - '0';
        a[len] += a[len - 1];
        ans += p[a[len] - len];
        p[a[len] - len]++;
        ch = getchar();
    }
}

inline void init() {
    p.clear();
    a[0] = 0;
    ans = 0;
}

int main() {
    scanf("%d", &T);
    while (T--) {
        init();
        scanf("%d", &n);
        p[0] = 1;
        read(a);
        printf("%lld\n", ans);
    }
    return 0;
}

D. Colored Rectangles

题意:

你有\(RGB\)三种颜色的木棍。告诉你每种颜色的木棍有几。问你用这些木棍凑出来所有矩形面积之和最大是多少。凑矩形必须满足如下条件:

  1. 对边颜色相同
  2. 邻边颜色不同
  3. 一条边只能用一根木棍

思路:

用木棍凑面积我们很容易想到一种贪心策略,就是每次取最长的两组木棍凑成矩形。所以我们对每一组木棍长度由大到小排序后跑DP。用\(f_{i,j,k}\)表示使用了\(i\)根红木棍,\(j\)根绿木棍,\(k\)根蓝木棍凑出来所有矩形的最大面积之和。那么,我们有如下状态转移方程:

\[f_{i,j,k} = \operatorname{max}(f_{i-1,j-1,k} + R_i \times G_j, f_{i - 1, j, k - 1} + R_i \times B_k, f_{i, j - 1, k - 1} + G_j \times B_k) \]

代码:

#include <cstdio>
#include <algorithm>
#include <map>
#include <queue>
typedef long long ll;

using namespace std;

ll color[3], f[205][205][205];
ll q[3][205];

bool cmp(const ll &a, const ll &b) {
    return a > b;
}

int main() {
    for (int i = 0; i < 3; i++)
        scanf("%lld", color + i);
    for (int i = 0; i < 3; i++) {
        for (int j = 1; j <= color[i]; j++) {
            scanf("%lld", &q[i][j]);
        }
    }

    for (int i = 0; i < 3; i++)
        sort(q[i] + 1, q[i] + color[i] + 1, cmp);
        
    ll ans = 0;
    for (int i = 0; i <= color[0]; i++) {
        for (int j = 0; j <= color[1]; j++) {
            for (int k = 0; k <= color[2]; k++) {
                if ((i + j + k) & 1) continue;
                if (!(i + j + k)) continue;
                if (i >= 1 && j >= 1) f[i][j][k] = max(f[i][j][k], f[i - 1][j - 1][k] + q[0][i] * q[1][j]);
                if (i >= 1 && k >= 1) f[i][j][k] = max(f[i][j][k], f[i - 1][j][k - 1] + q[0][i] * q[2][k]);
                if (j >= 1 && k >= 1) f[i][j][k] = max(f[i][j][k], f[i][j - 1][k - 1] + q[1][j] * q[2][k]);

                ans = max(ans, f[i][j][k]);
            }
        }
    }

    printf("%lld\n", ans);
    return 0;
}
posted @ 2020-08-15 11:32  icysky  阅读(201)  评论(0编辑  收藏  举报