Atcoder Beginner Constest abc 343 A-F题解

A- Wrong Answer

思路:

  • 跳过

第一种写法

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

#define endl '\n'
const int N = 2e3 + 5;
using ll = long long;


void solve()
{
    int a, b;
    cin >> a >> b;
    for(int i = 0; i < 10; i ++)
    {
        if(i != a + b)
        {
            cout << i << endl;
            return ;
        }
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    int t = 1;
    //cin >> t;
    while(t --)
        solve();

    return 0;
}

第二种写法——jiangly

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int a, b;
    cin >> a >> b;
    cout << !(a + b) << endl;

    return 0;
}

B- Adjacency Matrix

思路:

  • 数据量不大,枚举模拟即可

第一种写法

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

#define endl '\n'
const int N = 1e2 + 10;
using ll = long long;
int a[N][N];

void solve()
{
    int n;
    cin >> n;
    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= n; j ++)
            cin >> a[i][j];
    for(int i = 1; i <= n; i ++)
    {
        vector<int> v;
        for(int j = 1; j <= n; j ++)
        {
            if(a[j][i])
                v.push_back(j);
        }
        for(int j = 0; j < v.size(); j ++)
            cout << v[j] << " \n"[j == v.size() - 1];
    }

}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    int t = 1;
    //cin >> t;
    while(t --)
        solve();

    return 0;
}

第二种写法——jiangly

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int n;
    cin >> n;
    for(int i = 1; i <= n; i ++)
    {
        for(int j = 1; j <= n; j ++)
        {
            int a;
            cin >> a;
            if(a)
                cout << j << ' ';
        }
        cout << '\n';
    }

    return 0;
}

C - 343

思路:

  • 1 ≤ i ≤ 1 e 6 1\leq i \leq1e6 1i1e6,数据量不大,可以轻松枚举。
  • 只需每次判断是否为回文数即可

第一种写法

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

#define endl '\n'
const int N = 1e2 + 10;
using ll = long long;
//判断是否为回文数
bool check(ll n)
{
    string s;
    //拆解,并存入s中
    while(n)
    {
        s += n % 10 + '0';
        n /= 10;
    }
    int len = (int)s.size();
    s = '$' + s;
	//回文数具有对称性,判断
    for(int i = 1; i <= len / 2; i ++)
        if(s[i] != s[len - i + 1])
            return false;
    return true;
}
void solve()
{
    ll n, i;
    cin >> n;
    for(i = 1e6; i * i * i > n; i --);
    for(; i * i * i >= 1; i --)
    {
        ll temp = i * i * i;
        if(check(temp))
        {
            cout << temp << endl;
            return ;
        }
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    int t = 1;
    //cin >> t;
    while(t --)
        solve();

    return 0;
}

第二种写法——jiangly

#include <bits/stdc++.h>

using i64 = long long;

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    i64 n;
    std::cin >> n;
    i64 ans = 0;
    for(i64 a = 1; a * a * a <= n; a ++)
    {
        i64 x = a * a * a;
        //转换成string类型
        std::string s = std::to_string(x);
        //只要转置之后与原字符串相等,就是回文数
        //相当于reverse,但不会对字符串本身进行修改。
        if(s == std::string(s.rbegin(), s.rend()))
            ans = a * a * a;
    }
    std::cout << ans << '\n';

    return 0;
}

D - Diversity of Scores

思路:

  • 用两个map模拟:
    • 一个储存为 m p 1 [ 选手编号,该选手分数 ] mp1[选手编号, 该选手分数] mp1[选手编号,该选手分数]
    • 一个储存为 m p 2 [ 分数,为此分数的人数 ] mp2[分数,为此分数的人数] mp2[分数,为此分数的人数]

第一种写法

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

#define endl '\n'
const int N = 2e5 + 10;
using ll = long long;
map<int, ll> mp;
map<ll, int> mp1;
int a[N], b[N];
void solve()
{
    int n, t;
    cin >> n >> t;
    //输入
    for(int i = 1; i <= t; i ++)
        cin >> a[i] >> b[i];
    mp1[0] = n;
    for(int i = 1; i <= t; i ++)
    {
    	//分数进行了变化,原来的分数的人输-1
        mp1[mp[a[i]]] --;
        //如果原来的分数的人数变为1,则删除mp1此分数结点
        if(mp1[mp[a[i]]] == 0)
            mp1.erase(mp[a[i]]);//删除
        //加分
        mp[a[i]] += b[i];
        //加分后的分数的人数+1
            mp1[mp[a[i]]] ++;
        //输出第二种mp的尺寸即可
        cout << mp1.size() << endl;
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    int t = 1;
    //cin >> t;
    while(t --)
        solve();

    return 0;
}

第二种写法——jiangly

#include <bits/stdc++.h>

using i64 = long long;

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n, t;
    std::cin >> n >> t;

    //存储这个分数有多少人
    std::map<i64, int> cnt;
    //存储这个序号的选手有多少分数
    std::vector<i64> score(n);
    //初始都为每个人的分数都为0
    cnt[0] = n;
    while(t --)
    {
        int a, b;
        //输入
        std::cin >> a >> b;
        //使序号统一
        a --;
        //若原分数人数减一后为零,直接删除该结点
        if(-- cnt[score[a]] == 0)
            cnt.erase(score[a]);
        //加分
        score[a] += b;
        //此分数人数+1
        cnt[score[a]] ++;
        //输出尺寸
        std::cout << cnt.size() << '\n';
    }

    return 0;
}

E - 7x7x7

参考来源——abc官方题解

思路:

  • 把其中一个正方体固定在: ( 0 , 0 , 0 ) (0, 0, 0) (0,0,0)位置是可行的。因为所求的答案只与三个立方体的相对位置相关。而题目所限制的 a , b , c a,b,c a,b,c的范围足够大。因此可行。

  • 那么难点主要就是求 V 1 , V 2 , V 3 V1,V2,V3 V1,V2,V3的大小。由题目可得:

    • v 3 = V ( C 1 ∩ C 2 ∩ C 3 ) v_3=V(C_1\cap C_2\cap C_3) v3=V(C1C2C3)
    • v 2 = V ( C 1 ∩ C 2 ) + V ( C 1 ∩ C 3 ) + V ( C 2 ∩ C 3 ) − 3 v 3 v_2=V(C_1\cap C_2)+V(C_1\cap C_3)+V(C_2\cap C_3)-3v_3 v2=V(C1C2)+V(C1C3)+V(C2C3)3v3
    • v 1 = 3 × 7 3 − 2 v 2 − 3 v 3 v_1=3\times 7^3-2v_2-3v_3 v1=3×732v23v3
  • 最主要是求得 V 2 , V 3 V2,V3 V2,V3的体积的值,那如何去求:

  • 推导: ( 两个立方体的公共部分的长,宽,高 ) (两个立方体的公共部分的长,宽,高) (两个立方体的公共部分的长,宽,高)

  • max ⁡ { a i , a j } ≤ x ≤ min ⁡ { a i + 7 , a j + 7 } \max\{a_i,a_j\}\leq x\leq \min\{a_i+7,a_j+7\} max{ai,aj}xmin{ai+7,aj+7}

  • max ⁡ { b i , b j } ≤ y ≤ min ⁡ { b i + 7 , b j + 7 } \max\{b_i,b_j\}\leq y\leq \min\{b_i+7,b_j+7\} max{bi,bj}ymin{bi+7,bj+7}

  • max ⁡ { c i , c j } ≤ z ≤ min ⁡ { c i + 7 , c j + 7 } \max\{c_i,c_j\}\leq z\leq \min\{c_i+7,c_j+7\} max{ci,cj}zmin{ci+7,cj+7}

因此可以得到 max ⁡ { 0 , min ⁡ { a i , a j } + 7 − max ⁡ { a i , a j } } × max ⁡ { 0 , min ⁡ { b i , b j } + 7 − max ⁡ { b i , b j } } × max ⁡ { 0 , min ⁡ { c i , c j } + 7 − max ⁡ { c i , c j } } \max\{0, \min\{a_i,a_j\}+7-\max\{a_i,a_j\}\} \times \max\{0, \min\{b_i,b_j\}+7-\max\{b_i,b_j\}\} \times \max\{0,\min\{c_i,c_j\}+7-\max\{c_i,c_j\}\} max{0,min{ai,aj}+7max{ai,aj}}×max{0,min{bi,bj}+7max{bi,bj}}×max{0,min{ci,cj}+7max{ci,cj}}

  • 如果是三个立方体,依旧同理可得。

以下是代码部分:

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
//计算正方体两两公共的体积
int f(int a1, int b1, int c1, int a2, int b2, int c2) {
    int res = 1;
    res *= max(0, min(a1, a2) + 7 - max(a1, a2));
    res *= max(0, min(b1, b2) + 7 - max(b1, b2));
    res *= max(0, min(c1, c2) + 7 - max(c1, c2));
    return res;
}
// 计算正方体三三公共的体积
int f(int a1, int b1, int c1, int a2, int b2, int c2, int a3, int b3, int c3) {
    int res = 1;
    res *= max(0, min({a1, a2, a3}) + 7 - max({a1, a2, a3}));
    res *= max(0, min({b1, b2, b3}) + 7 - max({b1, b2, b3}));
    res *= max(0, min({c1, c2, c3}) + 7 - max({c1, c2, c3}));
    return res;
}

int main() {
    int v1, v2, v3;
    cin >> v1 >> v2 >> v3;
    //以固定C1,枚举C2,C3的位置。想要由公共体积,枚举范围为这些。
    for (int a2 = -7; a2 <= 7; a2++) {
        for (int b2 = -7; b2 <= 7; b2++) {
            for (int c2 = -7; c2 <= 7; c2++) {
                for (int a3 = -7; a3 <= 7; a3++) {
                    for (int b3 = -7; b3 <= 7; b3++) {
                        for (int c3 = -7; c3 <= 7; c3++)
                        {
                            //正方体三三公共的体积的值
                            int nv3 = f(0, 0, 0, a2, b2, c2, a3, b3, c3);
                            //正方体两两公共的体积的值的和
                            int nv2 = f(0, 0, 0, a2, b2, c2) + f(0, 0, 0, a3, b3, c3) + f(a2, b2, c2, a3, b3, c3) -
                                      nv3 * 3;
                            //正方体私有的体积的值的和
                            int nv1 = 3 * 7 * 7 * 7 - nv2 * 2 - nv3 * 3;
                            if (v1 != nv1 || v2 != nv2 || v3 != nv3) continue;
                            printf("Yes\n0 0 0 %d %d %d %d %d %d\n", a2, b2, c2, a3, b3, c3);
                            return 0;
                        }
                    }
                }
            }
        }
    }
    cout << "No" << endl;
}

F - Second Largest Query

这题可去B站观看视频讲解bilibili的一个up :tarjan98

思路:

  • 线段树储存该区段的最大值 m x 1 mx1 mx1, 最大值个数 c n t 1 cnt1 cnt1, 次大值 m x 2 mx2 mx2, 次大值个数 c n t 2 cnt2 cnt2

以下是代码部分——代码参考来源wsy0655

#include <bits/stdc++.h>
using namespace std;
#define ls p<<1
#define rs (p<<1)|1
using ll = long long;
const int N = 2e5 + 10;

int n, q, a[N];
//结点数量最大不超过4 * N
struct segment_tree{
    // l为左边界, r为右边界, cnt1为最大值的数量, cnt2为次大值的数量
    // mx1为最大值, mx2 为次大值
    int l, r, cnt1, cnt2, mx1, mx2;
}t[N << 2];

void push_up(int p)
{
    //最大值为左下分叉点和右下分叉结点中的最大值
    t[p].mx1 = max(t[ls].mx1, t[rs].mx1);
    //分情况归类mx1 和 mx2
    //最大值的数目更新
    if(t[ls].mx1 > t[rs].mx1) t[p].cnt1 = t[ls].cnt1;
    else if(t[ls].mx1 < t[rs].mx1) t[p].cnt1 = t[rs].cnt1;
    else t[p].cnt1 = t[ls].cnt1 + t[rs].cnt1;

    //map储存记录mx1, mx2的数目
    map<int, int> cnt;
    cnt[t[ls].mx1] += t[ls].cnt1;
    cnt[t[rs].mx1] += t[rs].cnt1;
    cnt[t[ls].mx2] += t[ls].cnt2;
    cnt[t[rs].mx2] += t[rs].cnt2;
    //map内部已经从小到大排序
    auto it = cnt.lower_bound(t[p].mx1);
    // 求出次大值的位置
    it --;
    //次大值赋值
    t[p].mx2 = it -> first;
    if(it->first == 0) t[p].cnt2 = 0;
    else t[p].cnt2 = cnt[it -> first];
}
//通过递归建立线段树
void build(int p, int l, int r)
{
    //该区段的左边界和右边界
    t[p].l = l, t[p].r = r;
    //当只有一个元素时, 结束递归
    if(l == r)
    {
        t[p].mx1 = a[l], t[p].mx2 = t[p].cnt2 = 0, t[p].cnt1 = 1;
        return ;
    }
    //计算中间值
    int mid = l + ((r - l) >> 1);
    //递归建立线段树,先建立左边的,再建立右边的。
    build(ls, l, mid), build(rs, mid + 1, r);
    push_up(p);
}

void modify(int p, int x, int k)
{
    if (x == t[p].l && t[p].r == x)
    {
        t[p].mx1 = k, t[p].mx2 = 0, t[p].cnt1 = 1, t[p].cnt2 = 0;
        return ;
    }
    int mid = (t[p].l + t[p].r) >> 1;
    if (x <= mid) modify(ls, x, k);
    if (x >  mid) modify(rs, x, k);
    push_up(p);
}
//和push_up()函数一个代码,为查询
segment_tree query(int p, int l, int r)
{
    //如果包含这个子段范围,直接返回
    if (l <= t[p].l && t[p].r <= r) return t[p];
    //中间区间边界
    int mid = (t[p].l + t[p].r) >> 1;
    //在右子段
    if (r <= mid) return query(ls, l, r);
    //在左子段
    if (l > mid) return query(rs, l, r);
    //x为左子段返回内容, y为右子段返回内容
    segment_tree x = query(ls, l, r), y = query(rs, l, r), res;
    //比较左右子段哪个更好
    //分类讨论赋最大值的值
    res.mx1 = max(x.mx1, y.mx1);
    if (x.mx1 > y.mx1) res.cnt1 = x.cnt1;
    else if (x.mx1 < y.mx1) res.cnt1 = y.cnt1;
    else res.cnt1 = x.cnt1 + y.cnt1;
    //次大值赋值
    map<int, int> cnt;
    cnt[x.mx1] += x.cnt1;
    cnt[y.mx1] += y.cnt1;
    cnt[x.mx2] += x.cnt2;
    cnt[y.mx2] += y.cnt2;
    auto it = cnt.lower_bound(res.mx1);
    it--;
    res.mx2 = it->first;
    if (it->first == 0) res.cnt2 = 0;
    else res.cnt2 = cnt[it->first];
    return res;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> q;
    for (int i = 1; i <= n; i++) cin >> a[i];
    build(1, 1, n);
    while (q--)
    {
        int op, l, r;
        cin >> op >> l >> r;
        if (op == 1) modify(1, l, r);
        if (op == 2) cout << query(1, l, r).cnt2 << "\n";
    }
    return 0;
}
  • 24
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代码,好简单。(请点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞)
AtCoder Beginner Contest 134 是一场 AtCoder 的入门级比赛,以下是每道题的简要题解: A - Dodecagon 题目描述:已知一个正十二边形的边长,求它的面积。 解题思路:正十二边形的内角为 $150^\circ$,因此可以将正十二边形拆分为 12 个等腰三角形,通过三角形面积公式计算面积即可。 B - Golden Apple 题目描述:有 $N$ 个苹果和 $D$ 个盘子,每个盘子最多可以装下 $2D+1$ 个苹果,求最少需要多少个盘子才能装下所有的苹果。 解题思路:每个盘子最多可以装下 $2D+1$ 个苹果,因此可以将苹果平均分配到每个盘子中,可以得到最少需要 $\lceil \frac{N}{2D+1} \rceil$ 个盘子。 C - Exception Handling 题目描述:给定一个长度为 $N$ 的整数序列 $a$,求除了第 $i$ 个数以外的最大值。 解题思路:可以使用两个变量 $m_1$ 和 $m_2$ 分别记录最大值和次大值。遍历整个序列,当当前数不是第 $i$ 个数时,更新最大值和次大值。因此,最后的结果应该是 $m_1$ 或 $m_2$ 中较小的一个。 D - Preparing Boxes 题目描述:有 $N$ 个盒子和 $M$ 个物品,第 $i$ 个盒子可以放入 $a_i$ 个物品,每个物品只能放在一个盒子中。现在需要将所有的物品放入盒子中,每次操作可以将一个盒子内的物品全部取出并分配到其他盒子中,求最少需要多少次操作才能完成任务。 解题思路:首先可以计算出所有盒子中物品的总数 $S$,然后判断是否存在一个盒子的物品数量大于 $\lceil \frac{S}{2} \rceil$,如果存在,则无法完成任务。否则,可以用贪心的思想,每次从物品数量最多的盒子中取出一个物品,放入物品数量最少的盒子中。因为每次操作都会使得物品数量最多的盒子的物品数量减少,而物品数量最少的盒子的物品数量不变或增加,因此这种贪心策略可以保证最少需要的操作次数最小。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值