Codeforces Global Round 4

Contest Info


Practice Link

Solved A B C D E F1 F2 G H
5/9 O O O O O - - - -
  • O 在比赛中通过
  • Ø 赛后通过
  • ! 尝试了但是失败了
  • - 没有尝试

Solutions


A. Prime Minister

签到题。

#include <bits/stdc++.h>
using namespace std;
 
#define N 110
int n, a[N], b[N];
 
int main() {
    while (scanf("%d", &n) != EOF) {
        memset(b, 0, sizeof b);
        int sum = 0, other = 0;
        for (int i = 1; i <= n; ++i) scanf("%d", a + i), sum += a[i];
        b[1] = 1;
        other = a[1];
        for (int i = 2; i <= n; ++i) {
            if (a[1] >= a[i] * 2) {
                other += a[i];
                b[i] = 1;
            }
        }
        if (other > sum / 2) {
            int sze = 0;
            vector <int> vec;
            for (int i = 1; i <= n; ++i) {
                if (b[i]) {
                    ++sze;
                    vec.push_back(i);
                }
            }
            printf("%d\n", sze);
            for (int i = 0; i < sze; ++i) printf("%d%c", vec[i], " \n"[i == sze - 1]);
        } else {
            puts("0");
        }
    }
    return 0;
}

B. WOW Factor

题意:
将连续的两个\(v\)可以看成一个\(w\),询问给出的字符串中只包含字符\(v\)\(o\),询问有多少个子序列组成\(wow\)

思路:
先处理出每个\(o\)左边有多少个\(w\)以及右边有多少个\(w\),然后计算贡献即可。

代码:

#include <bits/stdc++.h>
using namespace std;
 
#define ll long long
#define N 1000010
int n;
ll l[N], r[N];
char s[N];
 
int main() {
    while (scanf("%s", s + 1) != EOF) {
        n = strlen(s + 1);
        l[0] = 0;
        for (int i = 1; i <= n; ++i) {
            l[i] = l[i - 1];
            if (i > 1 && s[i] == 'v' && s[i - 1] == 'v') {
                ++l[i];
            }
        }
        r[n + 1] = 0;
        for (int i = n; i >= 1; --i) {
            r[i] = r[i + 1];
            if (i < n && s[i] == 'v' && s[i + 1] == 'v') {
                ++r[i];
            }
        }
        ll res = 0;
        for (int i = 1; i <= n; ++i) {
            if (s[i] == 'o') {
                res += 1ll * l[i - 1] * r[i + 1];
            }
        }
        printf("%lld\n", res);
    }
    return 0;
}

C. Tiles

题意:
有这样的瓷砖:

用来拼\(n \cdot m\)的地板,要求任意相邻的边两边的颜色不能相同。

思路:
显然第一个位置可以有四种选择,并且第一排的后面的每个位置都有两种选择,因为不能和前面的边相同。
那么第一列后面的位置也有两种选择,那么剩下的位置都只有一种选择,因为它们相邻了两条边。
所以答案就是\(4 \cdot 2^{n + m - 2}\)

代码:

#include <bits/stdc++.h>
using namespace std;
 
#define ll long long
const ll p = 998244353;
 
ll qmod (ll base, ll n) {
    ll res = 1;
    while (n) {
        if (n & 1) {
            res = res * base % p;
        }
        base = base * base % p;
        n >>= 1;
    }
    return res;
}
 
int main() {
    int n, m;
    while (scanf("%d%d", &n, &m) != EOF) {
        printf("%lld\n", qmod(2, n - 1) * qmod(2, m - 1) % p * 4 % p);
    }
    return 0;
}

D. Prime Graph

题意:
给出\(n\)个点,要求构成一个简单图,使得边的总数是素数,并且每个点的度数也是素数。

思路:

  • 首先考虑每个点的度数至少为\(2\),那么先把这些点连成一个环,所有点的度数就是\(2\)了。
  • 再考虑边的数量是素数,一个显然的想法是所有数都可以表示成\(2x + 3y\)的形式,所以我们将环中的点分成两部分,每次各取一个点连边,就增加一条边,并且让两个度数为\(2\)的点变成度数为\(3\)的。
  • 那么只要满足我们找一个\(>= n\)的最近的素数\(y\),使得\(y - n \leq \frac{n}{2}\)即可这样构造。
  • 素数的密度很高,或者\(n\)只有\(1000\)可以打表验证一下,这样是可以的。

代码:

#include <bits/stdc++.h>
using namespace std;
 
#define N 1010
#define pii pair <int, int>
#define fi first
#define se second
int n;
 
bool isprime(int x) {
    for (int i = 2; i < x; ++i) {
        if (x % i == 0) return 0;   
    }
    return 1;
}
 
int main() {
    while (scanf("%d", &n) != EOF) {
        int tot = n;
        for (int i = tot; ; ++i) {
            if (isprime(i)) {
                tot = i;
                break;
            }
        }
        vector <pii> vec;
        for (int i = 2; i <= n; ++i) vec.push_back(pii(i - 1, i));
        vec.push_back(pii(1, n));
        int remind = tot - n;
        int pos = n / 2 + 1; 
        for (int i = 1; i <= remind; ++i) {
            vec.push_back(pii(i, pos));
            ++pos;  
        }
        printf("%d\n", tot);
        for (auto it : vec) printf("%d %d\n", it.fi, it.se); 
    }
    return 0;
}

E. Archaeology

题意:
给出一个只包含'a', 'b', 'c'的字符串,保证任意两个连续的字符都不相同,要求选出一个子序列\(t\)使得它是一个回文串,并且\(|t| \geq \left\lfloor \frac{|s|}{2} \right\rfloor\)

思路:
贪心从两端取即可。
因为左端的两个字符和右端的两个字符,必然会有两个相等,因为保证了任意两个连续的字符不同,那么这样就是说每\(4\)个字符,至少有\(2\)个有贡献,显然满足题目限制。
其实也可以枚举一样,看看:
假如左端的\(ab\),那么右端的取值有以下几种:

  • \(ab\)
  • \(ac\)
  • \(bc\)
    显然都满足要求。

代码:

#include <bits/stdc++.h>
using namespace std;
 
#define N 1000010
#define INF 0x3f3f3f3f
int n, m, f[N][3], g[N][3], nx[3];
char s[N], t[N];
int vis[N];
 
bool ok() {
    m = 0;
    for (int i = 1; i <= n; ++i) if (vis[i]) {
        t[++m] = s[i]; 
    }
    t[m + 1] = 0;
    if (m >= n / 2) {
        printf("%s\n", t + 1);
        return 1;
    }
    return 0;
}
 
int main() {
    while (scanf("%s", s + 1) != EOF) {
        n = strlen(s + 1);
        for (int i = 1; i <= n; ++i) vis[i] = 0;
        nx[0] = nx[1] = nx[2] = 0;
        for (int i = 1; i <= n + 1; ++i) {
            for (int j = 0; j < 3; ++j) {
                g[i][j] = nx[j];
            }
            if (i <= n) {
                nx[s[i] - 'a'] = i;
            }
        }
        nx[0] = nx[1] = nx[2] = n + 1;
        for (int i = n; i >= 0; --i) {
            for (int j = 0; j < 3; ++j) {
                f[i][j] = nx[j];
            }
            if (i > 0) {
                nx[s[i] - 'a'] = i;
            }
        }
        int l = 0, r = n + 1;
        while (l <= r) {
            int Min = INF, pos = -1;
            for (int i = 0; i < 3; ++i) {
                if (f[l][i] < g[r][i] && f[l][i] - l + r - g[r][i] < Min) {
                    Min = f[l][i] - l + r - g[r][i];
                    pos = i;
                }
            }
            if (pos == -1) break;
            l = f[l][pos];
            r = g[r][pos];
            vis[l] = vis[r] = 1;
        }
        if (l < r - 1) {
            vis[l + 1] = 1;
        }
        if (!ok()) printf("IMPOSSIBLE\n");
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Dup4/p/11220155.html