AtCoder Beginner Contest 236 A-F

AtCoder Beginner Contest 236

今日vp
补题:EF
F是个线性基

A - chukodai

交换两个字符的位置

#include <bits/stdc++.h>

using namespace std;

int main () {
    string s;
    cin >> s;
    int a, b;
    cin >> a >> b;
    a --, b --;
    swap (s[a], s[b]);
    cout << s;
}

B - Who is missing?

1-n的数字中只有1个数字出现3次,其余数字都出现四次
找出那个特殊的数字

#include <bits/stdc++.h>

using namespace std;

int main () {
    int n;
    cin >> n;
    n = 4*n-1;
    map <int, int> mp;
    while (n --) {
        int x;
        cin >> x;
        mp[x] ++;
    }
    for (auto i : mp) {
        if (i.second == 3) {
            cout << i.first << endl;
            break;
        }
    }
}

C - Route Map

字符串Si如果在T中出现过就输出yes,否咋No

#include <bits/stdc++.h>

using namespace std;
const int N = 1e5 + 5;
string a[N];

int main () {
    int n, m;
    cin >> n >> m;
    set<string> b;
    for (int i = 1; i <= n; i ++)   cin >> a[i];
    while (m --) {
        string t;
        cin >> t;
        b.insert (t);
    }
    for (int i = 1; i <= n; i ++) {
        if (b.count (a[i])) cout << "Yes\n";
        else    cout << "No\n";
    }
}

D - Dance

2n个人两两配对,若i与j配对(i<j),则所得价值为\(A_{i,j}\) 求最终所有人配对之后的价值最大异或和

dfs枚举每一种组合可能


#include <bits/stdc++.h>
#define int long long

using namespace std;
const int N = 20;
int a[N][N], n, ans;
bool vis[N];

void dfs (int cnt, int sum) {
    if (cnt == n/2) {
        ans = max (sum, ans);
        return ;
    }

    for (int i = 1; i <= n; i ++) {
        if (vis[i]) continue;
        for (int j = i+1; j <= n; j ++) {
            if (vis[j])   continue;
            vis[i] = vis[j] = true;
            dfs (cnt + 1, sum ^ a[i][j]);
            vis[i] = vis[j] = false;
        }
        break;
    }
}

signed main () {
    scanf ("%lld", &n);
    n *= 2;
    for (int i = 1; i < n; i ++)
        for (int j = i+1; j <= n; j ++) {
            scanf ("%lld", &a[i][j]);
            a[j][i] = a[i][j];
        }

    dfs (0, 0);
    cout << ans << endl;
}

E - Average and Median

给定数组a,要从a中选出一些数构成数组b,需要满足数组a中相邻的两个数至少有一个被选上。
问构造出的b的平均数和中位数的最大值。

二分答案 + dp(check)
具体如何check可看代码及下面注释
实数+整数二分

#include <bits/stdc++.h>

using namespace std;
const int N = 1e5 + 5;
const double eps = 1e-6;
int a[N], n;

bool check_mid (int mid) {
    vector <int> b(n), f(n);
    for (int i = 1; i <= n; i ++)   b[i-1] = (a[i]>=mid?1:-1);
    f[0] = b[0], f[1] = max(0, b[0]) + b[1];
    for (int i = 2; i < n; i ++) {
        f[i] = max (f[i-1], f[i-2]) + b[i];
    }
    return max (f[n-2], f[n-1]) > 0;
}

bool check_aver (double mid) {
    vector <double> b(n), f(n);
    for (int i = 1; i <= n; i ++)   b[i-1] = a[i] - mid;
    f[0] = b[0], f[1] = max(0.0, b[0]) + b[1];
    for (int i = 2; i < n; i ++) {
        f[i] = max (f[i-1], f[i-2]) + b[i];
    }
    return max (f[n-2], f[n-1]) >= 0.0;
}

void binary_mid () {
    int l = 0, r = 1e9;
    while (l < r) {
        int mid = l + r + 1 >> 1;
        if (check_mid(mid)) l = mid;
        else    r = mid - 1;
    }
    cout << l << endl;
}

void binary_aver () {
    double l = 0.0, r = 1e9;
    while (abs(r-l) > eps) {
        double mid = (l+r) / 2;
        if (check_aver(mid)) l = mid;
        else    r = mid;
    }
    cout << fixed << setprecision(6) << l << endl;
}

int main () {
    cin >> n;
    for (int i = 1; i <= n; i ++)   cin >> a[i];
    binary_aver(), binary_mid();
}

//相邻两个必须要选一个,
//求最大平均数和中位数

//至少要选(n+1)/2个

//3 4 5 9  ->  5.25
//3 4 5 9 2 -> 4

//二分(实数+整数)答案+dp
//check1: b[i]=a[i]-mid;
//check2: b[i]=(a[i]>=mid?1:-1);
//dp: f[i]=max(f[i-1],f[i-2])+b[i];
//ans: max(f[n-1], f[n-2]);

F - Spices

题意:在集合S中选择一些数字进行异或和
可以得到1∼2^n−1之间的所有数字,求最小的花费。

分析:线性基模板,只要学习了原理就能会了,可以看看大佬的笔记

#include <bits/stdc++.h>
#define int long long

using namespace std;
typedef pair<int, int> pii;
const int N = 20;
int c[N], n, m;

signed main () {
    cin >> n;
    m = 1 << n;
    vector <pii> v;
    for (int i = 1; i < m; i ++) {
        int x;
        cin >> x;
        v.push_back ({x, i});
    }
    sort (v.begin(), v.end()); //按照花费从小到大排

    int ans = 0;
    vector <int> t(n+1, 0); //线性基
    for (auto vi : v) {
        int val = vi.first, x = vi.second;
        for (int i = 0; i < n; i ++) {
            if ((x >> i & 1) == 0)  continue;
            if (t[i] == 0) { //更新线性基
                ans += val;
                t[i] = x;
                break;
            }
            else    x ^= t[i];
        }
    }

    cout << ans << endl;
}


//在集合S中选择一些数字进行异或和
//可以得到1∼2^n−1之间的所有数字,求最小的花费。

//线性基模板
posted @ 2022-08-11 22:14  Sakana~  阅读(61)  评论(0编辑  收藏  举报