AtCoder Beginner Contest 310 A-E题解

比赛链接https://atcoder.jp/contests/abc310
比赛时间:2023年7月15日 20:00-21:40

A题:Order Something Else

标签:模拟
题意:给定 n n n个商品的价格 d i d_i di元,现在推出一个饮料,原价 p p p元,如果买一个商品再买这个饮料只要 q q q元,求买这个饮料最少花多少钱。
题解:拿商品中的最低价格加上打折后饮料价格 q q q,和原价饮料价格 p p p进行对比,取最小值。
代码

#include <bits/stdc++.h>
using namespace std;

int main() {
    int n, p, q, d, mi = 1e9;
    cin >> n >> p >> q;
    for (int i = 1; i <= n; i++) {
        cin >> d;
        mi = min(mi, d);
    }
    cout << min(mi + q, p);
    return 0;
}

B题:Strictly Superior

标签:枚举、模拟
题意:给定 n n n个产品,第 i i i个产品 p i p_i pi元,且有 c i c_i ci个功能 f i , k f_{i,k} fi,k 1 < = k < = c i 1<=k<=c_i 1<=k<=ci)。题目求有没有以下所以条件的情况出现( 1 < = i , j < = n 1<=i,j<=n 1<=i,j<=n):

  1. p i > = p j p_i>=p_j pi>=pj
  2. j j j个产品有第 i i i个产品的所有功能
  3. 要么 p i > p j p_i>p_j pi>pj或者 第 j j j个产品功能比第 i i i个产品的功能至少多一个

题解:题意有点坑,第三个条件满足其中一个就可以了。解法就是按题目要求模拟一下,在 p i > = p j p_i>=p_j pi>=pj的情况下,去检测下第 j j j个产品功能有没有完全覆盖第 i i i个产品,并计数一下多的功能数。
代码

#include <bits/stdc++.h>
using namespace std;

int p[105], f[105][105];

int main() {
    bool ans = false;
    int n, m, c, x;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        cin >> p[i] >> c;
        for (int j = 1; j <= c; j++) {
            cin >> x;
            f[i][x] = 1;
        }
    }

    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if (i == j) continue;
            if (p[j] <= p[i]) {
                int cnt = 0;
                bool flag = 1;
                for (int k = 1; k <= m; k++) {
                    if (f[i][k] && !f[j][k]) {
                        flag = 0;
                        break;
                    }
                    else if (!f[i][k] && f[j][k]) {
                        cnt++;
                    }
                }
                if (flag == 1 && (cnt > 0 || p[j] < p[i])) {
                    ans = true;
                    break;
                }
            }
        }
    }
    
    if (ans) cout << "Yes";
    else cout << "No";
    return 0;
}

C题:Reversible

标签 S T L STL STL m a p map map
题意:给定 n n n个字符串,每个字符串可以翻转,如果两个字符串中其中一个翻转之后和另一个相同,认为这两个字符串也相同(比如 a b c abc abc c b a cba cba),题目求不同的字符串个数。
题解:用 m a p map map去标记下每个字符串的原串和翻转串,先检测一下,如果没有在 m a p map map中出现过,那就是新串,计数加一。
代码

#include <bits/stdc++.h>
using namespace std;

map<string, int> m;

int main() {
    int n, ans = 0;
    string s;
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> s;
        if (!m[s]) ans++;
        m[s]++;
        reverse(s.begin(), s.end());
        m[s]++;
    }
    cout << ans << endl;
    return 0;
}

D题:Peaceful Teams

标签:深搜 d f s dfs dfs、状压 d p dp dp
题意:给定 n n n个运动员要分成 t t t只队伍(每只队伍至少 1 1 1人),并且给定 m m m个矛盾关系 a i a_i ai运动员和 b i b_i bi运动员,分成的队伍中两两运动员之间不能有矛盾,求满足条件的方法数有多少种。
题解 n < = 10 n<=10 n<=10,考虑直接暴力搜索,暴力搜索的过程中需要考虑把第 i i i个人是分到新的一只队伍里面还是放在原来的前 m x mx mx只队伍里面,通过这样可以降低时间复杂度,不然如果选择把每个人往 1 − t 1-t 1t只队伍里面放一边,时间复杂度太高了。最后把第 n n n个人处理完之后,检测一下是否有矛盾冲突的情况。
代码

#include <bits/stdc++.h>
using namespace std;

int n, t, m, a[50], b[50], vis[50], ans = 0;

void dfs(int k, int mx) {
    if (k == n + 1) {
        if (mx != t) return ;
        for (int i = 1; i <= m; i++) {
            if (vis[a[i]] == vis[b[i]]) return ;
        }
        ans++;
        return;
    }
    for (int i = 1; i <= mx + 1; i++) {
        vis[k] = i;
        dfs(k + 1, max(i, mx));
        vis[k] = 0;
    }
}

int main() {
    cin >> n >> t >> m;
    for (int i = 1; i <= m; i++)
    cin >> a[i] >> b[i];
    dfs(1, 0);
    cout << ans;
    return 0;
}

E题:NAND repeatedly

标签:动态规划
题意:给定一个长度为 n n n 01 01 01字符串 A i A_i Ai,给定规则: 0 ⊼ 0 = 1 , 0 ⊼ 1 = 1 , 1 ⊼ 0 = 1 , 1 ⊼ 1 = 0 0⊼0=1,0⊼1=1,1⊼0=1,1⊼1=0 00=1,01=1,10=1,11=0

∑ i = 1 n ∑ j = i n f ( i , j ) \sum_{i=1}^n \sum_{j=i}^n f(i,j) i=1nj=inf(i,j) 1 < = i < = j < = n 1<=i<=j<=n 1<=i<=j<=n), f ( i , j ) = { A i ( i = j ) f ( i , j − 1 ) ⊼ A j ( i < j ) f(i,j)=\left\{\begin{matrix} A _ i&(i=j)\\ f(i,j-1)\barwedge A _ j\quad&(i\lt j) \end{matrix}\right. f(i,j)={Aif(i,j1)Aj(i=j)(i<j)
题解:显然我们可以通过 O ( n 2 ) O(n^2) O(n2)时间复杂度完成这道题要求,但是 n < = 1 0 6 n<=10^6 n<=106会超时。
d p [ i ] [ 0 / 1 ] dp[i][0/1] dp[i][0/1]:前 i i i个数字累计 n a n d ( ⊼ ) nand(⊼) nand 0 / 1 0/1 0/1的方案数。分以下两种情况考虑:

  1. 当前数字是 0 0 0 d p [ i ] [ 1 ] dp[i][1] dp[i][1]累计是 1 1 1的情况可以从前面 i − 1 i-1 i1累计是 0 0 0 1 1 1的情况转移过来,因为当前数字是 0 0 0,不管和 0 0 0 1 1 1 n a n d ( ⊼ ) nand(⊼) nand都是 1 1 1 d p [ i ] [ 0 ] dp[i][0] dp[i][0]累计是 0 0 0的情况初始化成 1 1 1
  2. 当前数字是 1 1 1 d p [ i ] [ 1 ] dp[i][1] dp[i][1]累计是 1 1 1的情况只能从前面 i − 1 i-1 i1累计是 0 0 0的情况转移过来,并且计数增加 1 1 1(算上自己本身的),因为 1 ⊼ 1 = 0 1⊼1=0 11=0 d p [ i ] [ 0 ] dp[i][0] dp[i][0]累计是 0 0 0的情况从前面 i − 1 i-1 i1累计是 1 1 1的情况转移过来。

最后把每个位置的 d p [ i ] [ 1 ] dp[i][1] dp[i][1]累加一下即可。
代码

#include <bits/stdc++.h>
using namespace std;

const int N = 1e6 + 10;
typedef long long ll;
ll dp[N][2];

int main() {
    ll n, ans = 0;
    string s;
    cin >> n >> s;
    for (int i = 1; i <= n; i++) {
        if (s[i-1] == '0') {
            dp[i][1] = dp[i-1][0] + dp[i-1][1];
            dp[i][0] = 1;
        } else {
            dp[i][1] = dp[i-1][0] + 1;
            dp[i][0] = dp[i-1][1];
        }
        ans += dp[i][1];
    }
    cout << ans << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值