首页 > 其他分享 >Codeforces Round 931 (Div. 2) A-D2

Codeforces Round 931 (Div. 2) A-D2

时间:2024-03-02 22:22:47浏览次数:21  
标签:cout int cin long using 931 D2 Div define

A. Too Min Too Max

贪心、排序

对数组排序后,显然当下标 \(i\)、\(j\)、\(k\)、\(l\) 分别选择 \(1\)、\(n\)、\(2\)、\(n - 1\) 时求得最大值。

时间复杂度:\(O(nlogn)\) 。

#include <bits/stdc++.h>

using namespace std;

#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define all(x) x.begin(), x.end()
#define ALL(x) x.begin() + 1, x.end()

using i64 = long long;

void solve() {
    int n;
    cin >> n;
    
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }

    sort(ALL(a));

    cout << 2 * (a[n] + a[n - 1] - a[1] - a[2]) << '\n';
}

void prework() {

}

int main() {
    cctie;

    prework();

    int T;
    cin >> T;

    while (T--) {
        solve();
    }

    return 0;
} 

B. Yet Another Coin Problem

枚举、贪心

价值为 \(1\) 的硬币最多需要 \(2\) 个,当需要 \(3\) 个及以上时,可由 价值更高的硬币替代;以此类推,价值为 \(3\)、\(6\)、\(10\) 的硬币分别最多需要 \(1\)、\(5\)、\(3\) 个,然后剩余需要补齐的价值均由价值为 \(15\) 的硬币补齐。则通过分别枚举价值 \(1\)、\(3\)、\(6\)、\(10\) 的硬币数量在所有可行解中取最小值为答案。

#include <bits/stdc++.h>

using namespace std;

#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define all(x) x.begin(), x.end()
#define ALL(x) x.begin() + 1, x.end()

using i64 = long long;

void solve() {
    int n;
    cin >> n;

    int ans = n;
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 2; j++) {
            for (int k = 0; k < 6; k++) {
                for (int l = 0; l < 3; l++) {
                    int x = n - i - j * 3 - k * 6 - l * 10;
                    if (x >= 0 && x % 15 == 0) {
                        ans = min(ans, i + j + k + l + x / 15);
                    }
                }
            }
        }
    }
    cout << ans << '\n';
}
 
void prework() {

}

int main() {
    cctie;

    prework();

    int T;
    cin >> T;

    while (T--) {
        solve();
    }

    return 0;
} 

C. Find a Mine

数学

随机选择一个点作为询问点时,距离询问点最近的雷可能存在的位置太多,不好在 \(4\) 次询问中确定一个雷的具体位置。而通过第一个样例的提示,我们发现当询问点为两条边界的交点时,可以得到距离最近的地雷可能的位置会在一条直线上,则我们的策略为选择三个这样的点(因为会受另一个地雷的干扰,仅选两个点是不够的),不妨选择 \((1, 1)\)、\((1, m)\)、\((n, 1)\) ,依次询问可得到三条直线,三条直线上点的坐标均可由二元一次方程表示,解方程组并判断合法性即可求得交点。画图可知,交点的数量可能为 \(1\) 或 \(2\) ,若为 \(1\) 时,显然交点即为所求点;若为 \(2\) 时,则第 \(4\) 次询问用于筛除其中一点。

时间复杂度:\(O(1)\) 。

#include <bits/stdc++.h>

using namespace std;

#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define all(x) x.begin(), x.end()
#define ALL(x) x.begin() + 1, x.end()

using i64 = long long;

int ask(int x, int y) {
    cout << "? " << x << " " << y << endl;
    int d;
    cin >> d;
    return d;
}

void get(int x, int y) {
    cout << "! " << x << " " << y << endl;
}

void solve() {
    int n, m;
    cin >> n >> m;

    int d1 = ask(1, 1), d2 = ask(1, m), d3 = ask(n, 1);
    int x1 = (d1 + d2 + 3 - m) / 2, y1 = x1 - (d2 - m + 1);
    int y2 = (d1 + d3 + 3 - n) / 2, x2 = y2 - (d3 - n + 1);
    
    auto is_legal = [&](int x, int y)->bool {
        return 1 <= x && x <= n && 1 <= y && y <= m && x + y == 2 + d1;
    };

    if (is_legal(x1, y1)) {
        if (is_legal(x2, y2)) {
            int d = ask(x1, y1);
            if (d) {
                get(x2, y2);
            } else {
                get(x1, y1);
            }
        } else {
            get(x1, y1);
        }
    } else {
        get(x2, y2);
    }
}
 
void prework() {

}

int main() {
    cctie;

    prework();

    int T;
    cin >> T;

    while (T--) {
        solve();
    }

    return 0;
} 

D1. XOR Break — Solo Version

位运算、分类讨论

这里讨论一种最多只需要操作 2 次的做法。

当二进制数 \(n\) 包含 \(1\) 的个数为 \(1\) 时,显然对 \(n\) 已无法进行任何操作,因为选择任意一个比 \(n\) 小的数 \(y\) 来异或时,\(y\) 数位为 \(1\) 时 \(n\) 显然不为 \(1\),则 \(n \lt n \oplus y\) ;

当二进制数 \(n\) 包含多个 \(1\) 时,我们可以进行一种核心操作拆 \(1\) 补 \(1\) 的操作,比如 \(n = 101001\),我们可以选择 \(y = 001110\) 与 \(n\) 异或,得 \(1001111\) ,即拆了某个非最高位的 \(1\) 然后使该位之后的所有数位都为 \(1\) ,这是一种拆非最高位的操作,当然也可以拆最高位,刚刚的例子里,\(n\) 不变,我们可以选择 \(y = 100110\) 与 \(n\) 异或,得 \(001111\) ,即使得次高位及其之后的所有位为 \(1\) 。通过刚才的例子我们发现,我们没法在最高位和次高位的两个 \(1\) 之间进行任何拆补操作,所以当在这些位中 \(m\) 为 \(1\) 而 \(n\) 为 \(0\) 时,则无法实现转换,否则我们可以通过拆补来实现 \(n\) 到 \(m\) 的转换。

当 \(m\) 在 \(n\) 的最高位 \(1\) 的数位上为 \(0\) 时,我们则考虑拆最高位;当 \(m\) 在 \(n\) 的最高位 \(1\) 的数位上为 \(1\) 时,我们则考虑拆从高位往低位第一个出现的 \(n\) 为 \(1\) 且 \(m\) 为 \(0\) 的 \(1\);

拆补完后,可以一步转换成 \(m\),因为 \(n\) 在被拆的 \(1\) 的数位及其所有高位都与 \(m\) 相等,而其所有低位都已为 \(1\),对每一位 \(1\) 到 \(0\) 的转换是可以直接进行的(通过异或)。

#include <bits/stdc++.h>

using namespace std;

#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define all(x) x.begin(), x.end()
#define ALL(x) x.begin() + 1, x.end()

using i64 = long long;

void solve() {
    i64 n, m;
    cin >> n >> m;

    if (__builtin_popcountll(n) == 1) {
        cout << -1 << '\n';
    } else {
        int h = 0, k = 0;
        for (int i = 62; ~i; i--) {
            int u = n >> i & 1, v = m >> i & 1;
            if (u) {
                if (!h) {
                    h = i;
                }
                if (!v) {
                    k = i;
                    break;
                }
            }
        }

        vector<i64> ans(1, n);
        n -= 1LL << k;
        if (h == k) {
            int lh;
            for (int i = h - 1; ~i; i--) {
                int u = n >> i & 1, v = m >> i & 1;
                if (v > u) {
                    cout << -1 << '\n';
                    return;
                }
                if (u) {
                    lh = i;
                    break;
                }
            }
            k = lh;
        }
        for (int i = k - 1; ~i; i--) {
            int u = n >> i & 1;
            if (!u) {
                n += 1LL << i;
            }
        }
        ans.push_back(n);
        if (n != m) {
            ans.push_back(m);
        }

        cout << ans.size() - 1 << '\n';
        for (i64 i : ans) {
            cout << i << " \n"[i == m];
        }
    }
}

void prework() {

}

int main() {
    cctie;

    prework();

    int T;
    cin >> T;

    while (T--) {
        solve();
    }

    return 0;
} 

D2. XOR Break — Game Version

位运算、博弈论

我们先分析 \(n\) 中 \(1\) 的个数 \(k\) 较少的情况:\(k = 1\) 时,无法操作,先手必败;\(k = 2\) 时,先手可以拆成两个 \(k = 1\) 的数,先手必胜,不难想到 先手胜负 与 \(k\) 的奇偶有关,不妨。

当 k 为偶数时,一定可以分解成两个 \(k\) 为奇数的数;

当 \(k\) 为奇数时,如果是直接将所有为 \(1\) 的数位任意的分到两个数中,则一定有一个数的 \(k\) 为偶数,一个为奇数;如果用了 \(D1\) 中的拆分操作,则有一些数位由原本的 \(0\) 变为 \(1\) 和 \(1\) 变为 \(0\),当有一个 \(0\) 变为 \(1\) 时,分解后的两个数的 \(k\) 的奇偶性同时改变,\(1\) 变为 \(0\) 也是如此,而分解后的两个数的 \(k\) 奇偶性总是互异的,所以得出分解后的两个数的 \(k\) 一奇一偶。

所以我们得到偶必得奇且奇能得偶,而 \(k = 1\) 时无法操作且游戏为有限轮( \(D1\) 中的拆分操作是有限次的),得出 \(k\) 为偶数先手必胜, \(k\) 为奇数先手必败的结论。

由于操作次数限制在不超过 \(63\) 次,为了避免拆分操作不断添加 \(1\) 的数量而延长操作次数,每到 \(Alice\) 操作时,我们就选择将 \(n\) 分解成 \(n\) 的最高位和 \(n\) 的剩余部分,这样可以保证每次能将 \(1\) 的上限数量减一,这样则能保证操作次数在限制内。

#include <bits/stdc++.h>

using namespace std;

#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define all(x) x.begin(), x.end()
#define ALL(x) x.begin() + 1, x.end()

using i64 = long long;

void solve() {
    i64 n;
    cin >> n;

    int turn;
    if (__builtin_popcountll(n) & 1) {
        cout << "second" << endl;
        turn = 1;
    } else {
        cout << "first" << endl;
        turn = 0;
    }

    i64 p1 = 1, p2 = 1;
    while (p1 != 0 || p2 != 0) {
        if (turn == 0) {
            for (int i = 62; ~i; i--) {
                int u = n >> i & 1;
                if (u) {
                    p1 = 1LL << i;
                    break;
                }
            }
            p2 = n ^ p1;

            cout << p1 << " " << p2 << endl;
        } else {
            cin >> p1 >> p2;
            if (p1 == -1 && p2 == -1) {
                exit(0);
            }
            if (__builtin_popcountll(p1) % 2 == 0) {
                n = p1;
            } else {
                n = p2;
            }
        }
        turn ^= 1;
    }
}

void prework() {

}

int main() {
    cctie;

    prework();

    int T;
    cin >> T;

    while (T--) {
        solve();
    }

    return 0;
} 

标签:cout,int,cin,long,using,931,D2,Div,define
From: https://www.cnblogs.com/xiojoy/p/18042233

相关文章

  • 周赛Round26总结1
    预计得分500,实际得分400,挂了20+50+30分。T1移动move题目描述:\(n\)个二维向量\((X_{i},Y_{i})\),随便选择\(k\)个,其中\(0<=k<=n\),起点是\((0,0)\),每次移动后的位置是\((s+x_{i},t+y_{i})\),求终点\(|s|+|t|\)的最大值。分析:分类讨论。\((X_{i},Y_{i})\)可以分到四个......
  • Codeforces Round 926 (Div. 2)
    A-SashaandtheBeautifulArray难度:⭐题目大意给定一个长度为n的数组,其分数为An-An-1+An-1-An-2...+A2-A1;问如何排列可以让该数组的分数最大;解题思路就是让An-A1最大;神秘代码#include<bits/stdc++.h>#defineintlonglong#defineIOSio......
  • Codeforces Round 931 (Div. 2)
    CodeforcesRound931(Div.2)比赛链接A.TooMinTooMax思路这题一开始我以为就是简单的模拟一下,四个for循环可能就可以,事实上并不是,因为我们想让最后的值最大,所以我们可以将数组进行排序,之后我们从最左边取两个,最右边取两个,插着求绝对值的和就行Code#include<bits/stdc......
  • Codeforces Round 911 (Div. 2) vp D题
    前面三题,就B题一道900的题目让我wa了两发,而且有点难看出来主要是想不到。。不知道该怎么像。应该算是题目理解不清晰吧,很麻烦。。这个原因可以说是没有一个完整的思考路径,我能够直接想到答案接近的处理方法,但是细节上没有注意。在考虑问题的时候可能。。需要慢一些,太快了,容易漏......
  • div3笔记
     Problem-E-Codeforces这道题用了记录一个数末尾零的板子(敲重点)!!!再说一遍,简单博弈论就是贪心!1voidsolve(){2cin>>n>>m;3vector<int>a(n),b(n);4for(inti=0;i<n;i++)cin>>a[i];5intlen=0;//这组数字总共有几位,总长度6......
  • 2024 蓝桥杯模拟赛3(div1+div2)
    2024蓝桥杯模拟赛3(div1+div2)P8834[传智杯#3决赛]序列简单的模拟,数据范围很小,暴力即可点击查看代码#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;constintN=1e5+5;voidsolve(){ lln,k,a[N],cnt=0; cin>>n>>k; for(inti=1;i<=n;i++)c......
  • vue项目引入高德地图报错:Map container div not exist (火狐浏览器不加载地图)
    问题描述:谷歌浏览器正常显示地图,火狐浏览器不加载,并且报错:  Mapcontainerdivnotexist错误代码如下:  修改后代码如下:  参考大佬:https://blog.csdn.net/white_777/article/details/128286558  ......
  • Codeforces Round 930 (Div. 2) - sol
    20240301由于笔者实力较弱,所以这只是Div2的题解。四年一次的比赛啊,还是要打。Dashboard-CodeforcesRound930(Div.2)-CodeforcesA.ShufflePartyYouaregivenanarray\(a_1,a_2,\ldots,a_n\).Initially,\(a_i=i\)foreach\(1\lei\len\).Theopera......
  • Codeforces 1446D2 Frequency Problem (Hard Version)
    考虑求出全局的众数\(A\)。那么有一个结论,就是答案区间的众数中绝对有\(A\)。考虑反证法,如果没有\(A\),\(A\)在序列中出现的个数一定\(\ge\)区间内众数的出现个数,所以可以一直往外扩展直到\(A\)出现的个数与区间内非\(A\)众数的个数持平,这样肯定更优。于是可以考虑钦......
  • CF514D R2D2 and Droid Army(二分,ST表)
    传送门解题思路直接二分能干掉的人数,然后check函数枚举所有区间,因为m很小,所以可以用m个ST表预处理每个区间对应每个属性的最大值。一是需要注意二分的写法,而是注意check(0)时候的特判。AC代码#include<iostream>#include<algorithm>#include<cmath>#include<cstdio>#......