AcWing第6场周赛题解

A. AcWing 3733. 去掉一个元素

题目链接:https://www.acwing.com/problem/content/3736/

题目大意:问共有多少个元素满足,在去掉该元素后,剩余元素的相加之和为一个偶数(注意,0 也算偶数)。

解题思路:若和为奇数,答案为奇数个数;若和为偶数,答案为偶数个数。

示例程序:

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

int n, a, sum, cnt;

int main() {
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> a;
        sum += a;
        if (a % 2) cnt++;
    }
    if (sum%2) cout << cnt << endl;
    else cout << n - cnt << endl;
    return 0;
}

B. AcWing 3734. 求和

题目链接:https://www.acwing.com/problem/content/3737/

题目大意:按照题目描述求区间内所有数字的和。

解题思路:定义只包含 4 或 7 的数位 Lucky number,则我们其实可以直接由当前的数跳转到下一个 Lucky number,然后批量求和。Lucky number 其实没有多少,所以可以基于这样的思路进行模拟。

示例程序:

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

long long nxt(long long a) {
    long long t = 1, b = 0;
    while (a) {
        if (a % 10 == 4) {
            return (a + 3) * t + b;
        }
        b = b * 10 + 4;
        a /= 10;
        t *= 10;
    }
    return b * 10 + 4;
}

long long l, r, sum;

int main() {
    cin >> l >> r;
    for (long long a = 4; l <= r; a = nxt(a)) {
        if (a >= l) {
            long long p = min(a, r);
            sum += (p - l + 1) * a;
            l = p + 1;
        }
    }
    cout << sum << endl;
    return 0;
}

C. AcWing 3735. 构造完全图

题目链接:https://www.acwing.com/problem/content/3738/

题目大意:每次操作时,可以选择其中一个点,找到所有和它直接相连的点,使这些点两两之间连边(若两点之间已经存在边,则无需重复连接)。问,至少多少次操作以后,可以将整个图变为一个完全图?

解题思路:状压dp,基于一个贪心思想,思想来自于 题解视频 ,但是贪心思想的证明没有完全搞明白。每次选择一个点,则所有与这个点邻接的点都会加入这个点所在的极大连通子图,形成一个更大的极大连通子图。由于数据量比较小所以可以状态压缩。

示例程序参考了 我已经不想再做刺客了大佬的代码

示例程序:

#include <bits/stdc++.h>
using namespace std;
int f[1<<22], n, m, b[22];
pair<int, int> step[1<<22]; // {前一个状态, 选择的点}

int main() {
    cin >> n >> m;
    if (m == n*(n-1)/2) {   // 本身就是一个团
        cout << 0 << endl;
        return 0;
    }
    while (m--) {
        int u, v;
        cin >> u >> v;
        u--, v--;
        b[u] |= (1<<v);
        b[v] |= (1<<u);
    }
    memset(f, 0x3f, sizeof(f));
    for (int i = 0; i < n; i++) {
        b[i] |= (1<<i);
        f[b[i]] = 1;
        step[b[i]] = {0, i};
    }
    for (int st = 0; st < (1<<n); st++) {
        if (f[st] == 0x3f3f3f3f) continue;
        for (int i = 0; i < n; i++) {
            if (st & (1<<i)) {
                int st2 = st | b[i];
                if (f[st2] > f[st] + 1) {
                    f[st2] = f[st] + 1;
                    step[st2] = {st, i};
                }
            }
        }
    }
    int p = (1<<n) - 1;
    cout << f[p] << endl;
    while (p) {
        cout << step[p].second + 1 << " ";
        p = step[p].first;
    }
    return 0;
}
posted @ 2022-04-08 08:43  quanjun  阅读(23)  评论(0编辑  收藏  举报