AtCoder Beginner Contest 343 A~F

A.Wrong Answer(模拟)

题意:

给你两个整数AAABBB,它们介于000999之间。

输出任何一个介于000999之间且不等于A+BA+BA+B的整数。

分析:

按题意判断并输出一个整数即可。

代码:

#include<bits/stdc++.h>

using namespace std;

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

B.Adjacency Matrix(模拟)

题意:

有一个简单的无向图GGG,其中有NNN个顶点,顶点上标有数字1,2,…,N1,2,\ldots,N1,2,,N

给你GGG的邻接矩阵(Ai,j)(A_{i,j})(Ai,j)。也就是说,当且仅当Ai,j=1A_{i,j}=1Ai,j=1时,GGG有一条边连接顶点iiijjj

对于每个i=1,2,…,Ni=1,2,\ldots,Ni=1,2,,N,按升序输出与顶点iii直接相连的顶点的编号。

当且仅当顶点iiijjj之间有一条边相连时,顶点iiijjj才被认为是直接相连的。

分析:

如果是111代表连通,输出其索引即可。

代码:

#include<bits/stdc++.h>

using namespace std;

int main() {
    int n;
    cin >> n;
    for (int t = 1; t <= n; t++) {
        for (int i = 1; i <= n; i++) {
            int x;
            cin >> x;
            if (x)
                cout << i << ' ';
        }
        cout << endl;
    }
    return 0;
}

C.343(遍历)

题意:

给你一个正整数NNN

求一个不大于NNN的最大回文立方数。

正整数KKK只有在满足以下两个条件时才被定义为回文立方数:

  • 有一个正整数xxx,使得x3=Kx^3=Kx3=K.
  • KKK的十进制表示不含前导零,而且是一个回文数。更确切地说,如果用介于000999(含)之间的整数A0,A1,…,AL−2A_0,A_1,\ldots,A_{L-2}A0,A1,,AL2和介于111999(含)之间的整数AL−1A_{L-1}AL1KKK表示为K=∑i=0L−1Ai10iK=\sum\limits_{i = 0}^{L-1}A_i10^iK=i=0L1Ai10i,则所有i=0,1,…,L−1i=0,1,\ldots,L-1i=0,1,,L1都是Ai=AL−1−iA_i=A_{L-1-i}Ai=AL1i

分析:

nnn的范围是1e181e181e18, 所以只需要遍历到1e61e61e6即可,枚举然后判断是否为回文数即可。

代码:

#include<bits/stdc++.h>

typedef long long LL;
using namespace std;

bool check(LL n) {
    string s;
    while (n) {
        s += n % 10 + '0';
        n /= 10;
    }
    int len = s.size();
    s = '$' + s;
    for (int i = 1; i <= len / 2; i++)
        if (s[i] != s[len - i + 1])
            return false;
    return true;
}

int main() {
    LL n;
    cin >> n;
    LL ans = 1;
    for (LL i = 2; i * i * i <= n; i++) {
        LL temp = i * i * i;
        if (check(temp)) {
            ans = temp;
        }
    }
    cout << ans << endl;
    return 0;
}

D.Diversity of Scores(遍历)

题意:

高桥正在举办一场有NNN名选手参加的比赛,选手编号为111NNN。选手们将争夺积分。目前,所有棋手的积分都是零。

高桥的预知能力让他知道选手们的分数将如何变化。具体来说,对于i=1,2,…,Ti=1,2,\dots,Ti=1,2,,TAiA_iAi选手的分数将在iii秒后增加BiB_iBi分。

高桥希望分数多样化,他想知道在每个时刻棋手的分数中会出现多少个不同的分数值。对于每个i=1,2,…,Ti=1,2,\dots,Ti=1,2,,T,求从现在起i+0.5i+0.5i+0.5秒钟后玩家分数中不同分值的数量。

例如,如果在某一时刻球员的得分分别为101010202020303030202020,那么在该时刻球员的得分中有三个不同的分值。

分析:

初始化000NNN,开始肯定是111,因为都是000,可以用map<values值,人数>mpmap < values \text{值,人数} > mpmap<values,人数>mp来储存这个值,对于每一次相加B,mp[W[A]]B, mp[W[A]]B,mp[W[A]]就要减去一个人数到了新的地方,以此类推即可。

代码:

#include<bits/stdc++.h>

typedef long long LL;
using namespace std;
const LL N = 2e5 + 10;

map<LL, LL> mp;
LL W[N];

int main() {
    LL n, T;
    cin >> n >> T;
    mp[0] = n;
    LL ans = 1;
    for (LL i = 1; i <= T; i++) {
        LL A, B;
        cin >> A >> B;
        mp[W[A]]--;
        if (!mp[W[A]])
            ans--;
        W[A] += B;
        if (!mp[W[A]])
            ans++;
        mp[W[A]]++;
        cout << ans << endl;
    }
    return 0;
}

E.7x7x7(枚举)

题意:

在一个坐标空间中,我们想放置三个边长为777的立方体,这样正好一个、两个、三个立方体所包含区域的体积分别为V1V_1V1V2V_2V2V3V_3V3

对于三个整数aaabbbccc,让C(a,b,c)C(a,b,c)C(a,b,c)表示由(a≤x≤a+7)∧(b≤y≤b+7)∧(c≤z≤c+7)(a\leq x\leq a+7)\land(b\leq y\leq b+7)\land(c\leq z\leq c+7)(axa+7)(byb+7)(czc+7)代表的立方体区域。

判断是否有满足下列所有条件的九个整数a1,b1,c1,a2,b2,c2,a3,b3,c3a_1,b_1,c_1,a_2,b_2,c_2,a_3,b_3,c_3a1,b1,c1,a2,b2,c2,a3,b3,c3,如果存在,请找出一个这样的元组。

  • ∣a1∣,∣b1∣,∣c1∣,∣a2∣,∣b2∣,∣c2∣,∣a3∣,∣b3∣,∣c3∣≤100|a_1|,|b_1|,|c_1|,|a_2|,|b_2|,|c_2|,|a_3|,|b_3|,|c_3|\leq 100a1,b1,c1,a2,b2,c2,a3,b3,c3100
  • Ci=C(ai,bi,ci) (i=1,2,3)C_i=C(a_i,b_i,c_i)\ (i=1,2,3)Ci=C(ai,bi,ci) (i=1,2,3)
    • 恰好包含C1,C2,C3C_1,C_2,C_3C1,C2,C3中一个的区域的体积为V1V_1V1
    • 恰好包含两个C1,C2,C3C_1,C_2,C_3C1,C2,C3的区域的体积是V2V_2V2
    • 所有C1,C2,C3C_1,C_2,C_3C1,C2,C3所包含的区域的体积是V3V_3V3

分析:

假设第一个正方体的位置恒为(0,0,0)(0,0,0)(0,0,0),暴力枚举第二、三个正方体的位置,判断每种放置方法是否合法即可

对于枚举位置,让三个正方体离太远没有意义,只需要枚举所有能使得三个正方体相交或至少有一个面重合的最大范围即可,则可以枚举的第二个正方体的三个维度的坐标值在(0,7)(0,7)(0,7),第三个正方体的坐标值在(−7,14)(-7,14)(7,14)

代码:

#include<bits/stdc++.h>

using namespace std;

int get_d(int x, int tx) {
    return max(0, min(x, tx) + 7 - max(x, tx));
}

int get_d(int sx, int x, int tx) {
    return max(0, min({sx, x, tx}) + 7 - max({sx, x, tx}));
}

int fun(int ax, int ay, int az, int bx, int by, int bz) {
    int dx = get_d(ax, bx), dy = get_d(ay, by), dz = get_d(az, bz);
    return dx * dy * dz;
}

void solve() {
    int v1, v2, v3;
    cin >> v1 >> v2 >> v3;
    for (int x = 0; x <= 7; x++) {
        for (int y = 0; y <= 7; y++) {
            for (int z = 0; z <= 7; z++) {
                for (int tx = -7; tx <= 14; tx++) {
                    for (int ty = -7; ty <= 14; ty++) {
                        for (int tz = -7; tz <= 14; tz++) {
                            int dx = get_d(0, x, tx);
                            int dy = get_d(0, y, ty);
                            int dz = get_d(0, z, tz);
                            int tv3 = dx * dy * dz;
                            if (tv3 != v3)
                                continue;
                            int tv2 = fun(0, 0, 0, x, y, z) + fun(0, 0, 0, tx, ty, tz) + fun(x, y, z, tx, ty, tz) -
                                      3 * tv3;
                            if (tv2 != v2)
                                continue;
                            int tv1 = 3 * 7 * 7 * 7 - 3 * tv3 - 2 * tv2;
                            if (tv1 != v1)
                                continue;
                            cout << "Yes" << endl;
                            cout << "0 0 0 " << x << " " << y << " " << z << " " << tx << " " << ty << " " << tz
                                 << endl;
                            return;
                        }
                    }
                }
            }
        }
    }
    cout << "No" << endl;
}

int main() {
    solve();
    return 0;
}

F.Second Largest Query(线段树)

题意:

给你一个长度为NNN的序列A=(A1,A2,…,AN)A=(A_1,A_2,\ldots,A_N)A=(A1,A2,,AN)

按照给出的顺序处理QQQ个查询。每个查询属于以下两种类型之一:

  • 类型111:以1 p x的形式给出。将ApA_pAp的值改为xxx
  • 类型222:输出(Al,Al+1,…,Ar)(A_l,A_{l+1},\ldots,A_r)(Al,Al+1,,Ar)中第二大数值的出现次数。更准确地说,输出满足l≤i≤rl\leq i\leq rlir的整数iii的个数,即在Al,Al+1,…,ArA_l,A_{l+1},\ldots,A_rAl,Al+1,,Ar中正好有一个大于AiA_iAi的不同值。

分析:

可以直接用线段树维护四个信息,每个节点维护这个区间对应的最大值、次大值、以及他们各自的出现次数,使用线段树板子加上求第二大的数即可。

代码:

#include<bits/stdc++.h>

using namespace std;

template<class Info, class Merge = std::plus<Info>>

struct SegmentTree {
    const int n;
    const Merge merge;
    vector<Info> info;

    SegmentTree(int n) : n(n), merge(Merge()), info(4 << std::__lg(n)) {}

    SegmentTree(vector<Info> init) : SegmentTree(init.size()) {

        function<void(int, int, int)> build = [&](int p, int l, int r) {
            if (r - l == 1) {
                info[p] = init[l];
                return;
            }
            int m = (l + r) / 2;
            build(2 * p, l, m);
            build(2 * p + 1, m, r);
            pull(p);
        };

        build(1, 0, n);
    }

    void pull(int p) {
        info[p] = merge(info[2 * p], info[2 * p + 1]);
    }

    void modify(int p, int l, int r, int x, const Info &v) {
        if (r - l == 1) {
            info[p] = v;
            return;
        }
        int m = (l + r) / 2;

        if (x < m) {
            modify(2 * p, l, m, x, v);
        } else {
            modify(2 * p + 1, m, r, x, v);
        }
        pull(p);
    }

    void modify(int p, const Info &v) {
        modify(1, 0, n, p, v);
    }

    Info rangeQuery(int p, int l, int r, int x, int y) {
        if (l >= y || r <= x) {
            return Info();
        }
        if (l >= x && r <= y) {
            return info[p];
        }
        int m = (l + r) / 2;

        return merge(rangeQuery(2 * p, l, m, x, y), rangeQuery(2 * p + 1, m, r, x, y));
    }


    Info rangeQuery(int l, int r) {
        return rangeQuery(1, 0, n, l, r);
    }
};


struct Info {
    int mx1 = -1;
    int cnt1 = 0;
    int mx2 = -2;
    int cnt2 = 0;
};


Info operator+(Info a, Info b) {
    if (a.mx1 == b.mx1) {
        if (a.mx2 < b.mx2) {
            swap(a, b);
        }
        a.cnt1 += b.cnt1;
        if (a.mx2 == b.mx2) {
            a.cnt2 += b.cnt2;
        }
        return a;
    }
    if (a.mx1 < b.mx1) {
        swap(a, b);
    }
    if (b.mx1 > a.mx2) {
        a.mx2 = b.mx1;
        a.cnt2 = b.cnt1;
    } else if (b.mx1 == a.mx2) {
        a.cnt2 += b.cnt1;
    }
    return a;
}


int main() {
    int N, Q;
    cin >> N >> Q;
    vector<int> A(N);
    for (int i = 0; i < N; i++) {
        cin >> A[i];
    }

    SegmentTree<Info> seg(N);
    for (int i = 0; i < N; i++) {
        seg.modify(i, Info{A[i], 1, -1, 0});
    }

    while (Q--) {
        int type;
        cin >> type;

        if (type == 1) {
            int p, x;
            cin >> p >> x;
            p--;
            seg.modify(p, {x, 1, -1, 0});
        } else {
            int l, r;
            cin >> l >> r;
            l--;
            cout << seg.rangeQuery(l, r).cnt2 << endl;
        }
    }
    return 0;
}

赛后交流

在比赛结束后,会在交流群中给出比赛题解,同学们可以在赛后查看题解进行补题。

群号: 704572101,赛后大家可以一起交流做题思路,分享做题技巧,欢迎大家的加入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值