AtCoder Beginner Contest 167

Posted zdragon1104

tags:

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

传送门

A - Registration

技术图片
#include <bits/stdc++.h>
#define ll long long
using namespace std;
char s[15], t[15];
int main() {
    scanf("%s%s", s, t);
    bool flag = true;
    for(int i = 0 ; s[i]; i++) {
        if(s[i] != t[i]) flag = false;
    }
    printf("%s
", flag ? "Yes" : "No");
    return 0;
}
A.cpp

B - Easy Linear Programming

技术图片
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main() {
    int a, b, c, k;
    scanf("%d%d%d%d", &a, &b, &c, &k);
    int ans = 0;
    if(a > k) ans += k;
    else ans += a, k -= a;
    k = max(0, k - b);
    ans -= k;
    printf("%d
", ans);
    return 0;
}
B.cpp

C - Skill Up

题意:有N本书,M种算法,每种书的价格是Ci,第i书对第j种算法能提升Ai,j点,输出最少的钱满足每种算法的点数超过X。

数据范围:$ 1 leq N, M leq 12, 1 leq X,C_{i} leq 10^{5},0 leq A_{i,j} leq 10^{5} $

题解:N很小,状压枚举一下选那哪几本书,判断是否满足要求,并更新答案。

技术图片
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int c[15], a[15][15], n, m, x;
int main() {
    scanf("%d%d%d", &n, &m, &x);
    for(int i = 0; i < n; i++) {
        scanf("%d", &c[i]);
        for(int j = 0; j < m; j++) {
            scanf("%d", &a[i][j]);
        }
    }
    int ans = 1e9;
    for(int s = 1; s < 1 << n; s++) {
        vector<int> t(m, 0);
        int sum = 0;
        for(int i = 0; i < n; i++) {
            if((1 << i) & s) {
                sum += c[i];
                for(int j = 0; j < m; j++) {
                    t[j] += a[i][j];
                }
            }
        }
        bool flag = true;
        for(int i = 0; i < m; i++) {
            if(t[i] < x) flag = false;
        }
        if(flag) ans = min(ans, sum);
    }
    if(ans == 1e9) ans = -1;
    printf("%d
", ans);
    return 0;
}
C.cpp

D - Teleporter

题意:给一个长度为N的序列A,从1开始出发,每次传送至Ai,求传送K次后到达的位置。

数据范围:$ 2 leq N leq 2 imes 10^{5}, 1 leq A_{i} leq N, 1 leq K leq 10^{18} $

题解:找循环节起始位置和长度,然后判断K在循环节里面还是外面,在外面的话直接找,在里面的话对循环节长度取模找即可。

技术图片
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 2e5 + 5;
int a[N], n;
bool vis[N];
ll k;
int main() {
    scanf("%d%lld", &n, &k), k++;
    for(int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
    }
    int pos = 1;
    vector<int> vec;
    while(!vis[pos]) {
        vec.push_back(pos);
        vis[pos] = true;
        pos = a[pos];
    }
    if(k <= vec.size()) {
        printf("%d
", vec[k - 1]);
    }else {
        int t = a[vec[vec.size() - 1]], x;
        for(int i = 0; i < vec.size(); i++) {
            if(vec[i] == t) {
                x = vec.size() - i;
                break;
            }
            k--;
        }
        k %= x;
        t = vec[vec.size() - 1];
        while(k--) {
            t = a[t];
        }
        printf("%d
", t);
    }
    return 0;
}
D.cpp

E - Colorful Blocks

题意:N个块在一行,对每个块进行涂色,可以图M种颜色,求最多有K对相邻颜色相同的方案数。(mod 998244353)。

数据范围:$ 1 leq N,M leq 2 imes 10^{5},0 leq K leq N - 1  $

题解:令dp[i][j]代表涂1~i位置的块,有j对相邻颜色相同的方案数。

递推关系式:dp[i][j] = dp[i-1][j] *(M - 1) + dp[i-1][j-1]。可以发现,每一项都是 系数*m*(m-1)^x,而且系数是一个组合数,所以循环每项加起来即可。

技术图片
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 2e5 + 5;
const int MD = 998244353;
int f[N], fac[N], inv[N];
int quick_pow(int x, int y) {
    int ans = 1;
    while(y) {
        if(y & 1) ans = 1LL * ans * x % MD;
        y >>= 1;
        x = 1LL * x * x % MD;
    }
    return ans;
}
void init() {
    fac[0] = 1;
    for(int i = 1; i < N; i++) fac[i] = 1LL * fac[i - 1] * i % MD;
    inv[N - 1] = quick_pow(fac[N - 1], MD - 2);
    for(int i = N - 2; i >= 0; i--) inv[i] = 1LL * inv[i + 1] * (i + 1) % MD;
}
int C(int n, int m) {
    return 1LL * fac[n] * inv[m] % MD * inv[n - m] % MD;
}
int main() {
    init();
    int n, m, k;
    scanf("%d%d%d", &n, &m ,&k);
    f[0] = 1;
    for(int i = 1; i <= n; i++) {
        f[i] = 1LL * f[i - 1] * (m - 1) % MD;
    }
    int ans = 0;
    for(int i = 0; i <= k; i++) {
        ans = (ans + 1LL * C(n - 1, i) * f[n - i - 1] % MD) % MD;
    }
    ans = 1LL * ans * m % MD;
    printf("%d
", ans);
    return 0;
}
E.cpp

F - Bracket Sequencing

题意:给N个字符串,只包含‘(‘和‘)‘,求是否满足一种排序满足这N个字符串串联起来是个合法的括号序列。

数据范围:$ 1 leq N leq 10^{6} $

题解:判断一个字符串是否满足合法的括号序列,可以遍历字符串,如果遇到‘(‘,计数器加1,反之计数减1,只要任何时刻计数器不为负,且最后计数器为0,即为合法。

这里每一个字符串等价于X个‘)‘+Y个‘(‘,前面肯定需要左括号尽量多,所以将左括号大于右括号的字符串放前面,每放一个需要将计数器减去当前字符串右括号的个数,所以前面右括号越少越好。

对于右括号大于左括号的字符串,前面左括号越多越好。

技术图片
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e6 + 5;
char s[N];
vector<pair<int, int>> pa, pb;
int main() {
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; i++) {
        scanf("%s", s);
        int a = 0, b = 0;
        for(int j = 0; s[j]; j++) {
            if(s[j] == () a++;
            else if(a) a--;
            else b++;
        }
        if(a <= b) pa.push_back({a, b});
        else pb.push_back({a, b}); 
    }
    sort(pa.begin(), pa.end());
    sort(pb.begin(), pb.end(), [](pair<int, int> a, pair<int, int> b) {
        return a.second > b.second;
    });
    int sum = 0;
    bool flag = true;
    for(int i = 0; i < pa.size(); i++) {
        sum -= pa[i].first;
        if(sum < 0) flag = false;
        sum += pa[i].second;
    }
    for(int i = 0; i < pb.size(); i++) {
        sum -= pb[i].first;
        if(sum < 0) flag = false;
        sum += pb[i].second;
    }
    if(sum) flag = false;
    printf("%s
", flag ? "Yes" : "No");
    return 0;
}
F.cpp

 

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

AtCoder Beginner Contest 234

AtCoder Beginner Contest 115 题解

AtCoder Beginner Contest 154 题解

AtCoder Beginner Contest 103

AtCoder Beginner Contest 228

AtCoder Beginner Contest 242