首页 > 其他分享 >Codeforces Round 967 (Div. 2) ABCD

Codeforces Round 967 (Div. 2) ABCD

时间:2024-08-23 15:53:55浏览次数:6  
标签:ABCD 967 int cin long st num Div define

来源:Codeforces Round 967 (Div. 2)

做题时间:2024_08_21

A. Make All Equal

使所有元素相等的最小操作次数,就是保留最大的数字

所以操作次数就是总数减去数量最多得数

B. Generate Permutation

题意

构造一个序列 \(p\) ,内部元素是 \([1,2,\cdots,n]\) 打乱

使长度为 \(n\) 的初始值为 \(-1\) 的序列经过操作后变成 \(p\)

要求用两台打字机时的 \(carriage\; return\) 操作的次数相同

思路

思路就是先写几个序列出来

比如 \(1,2,3\) , \(3,1,2\) , \(2,1,3\) ,每个序列从后往前和从前往后的return次数相加是4,是 \(n+1\) ,所以就是偶数不行

至于奇数怎么构造,还是用\(1,2,3\) ,从后往前是return3次

那就先搞个 \([1,2,\cdots,n]\) 再把前 \(\frac{n+1}{2}\) 个逆序一下,比如4321567

从后往前和从前往后都是 \(\frac{n+1}{2}\) 次

C. Guess The Tree

题意

这是一个[[交互型问题]],通过询问至多 \(15n\) 次,来获取一个 \(n\) 个结点的树

思路

我们可以根据返回值判断两个结点是不是直接相连,比如 \(x,y\)

如果是就存储起来

如果不是,设返回值是 \(z\) ,我们再问询 \(x,z\) , \(y,z\)

我认为本题难度主要在于怎么组织代码

我是用一个 \(set\) 存储直接相连的点,用 \(map\) 存储所有询问过的结点

用一个队列存储上述的 \(x,z\) , \(y,z\)

代码

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

#define YES "Yes"
#define NO "No"
#define F first
#define S second
#define int long long
#define ull unsigned long long
#define endl "\n"
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
#define rep(i, j, k) for (int i = (j); i < (k); i++)
#define all(x) x.begin(), x.end()
#define vi vector<int>
#define pii pair<int, int>

signed main() {
    IOS;
    int t = 0;
    srand(time(0));
    cin >> t;
    while (t--) {
        int n, num;
        cin >> n;

        queue<pii> pq;         // 存查询
        set<pii> st;           // 存答案
        map<int, int> mp;      // 存点是否已被加入图中
        map<pii, int> mp_find; // 存是否查询过,也可以用set

        int root = rand() % n + 1;

        while (st.size() != n - 1) {
            if (pq.empty()) {
                for (int i = 1; i <= n; i++) {
                    if (i != root && mp[i] == 0) {
                        pq.push({min(root, i), max(root, i)});
                        break;
                    }
                }
            }
            while (pq.size()) {
                int x = pq.front().first;
                int y = pq.front().second;
                pq.pop();
                if (mp_find[{min(x, y), max(x, y)}] != 0) continue;
                
                cout << "? " << x << " " << y << endl;
                cout.flush();
                cin >> num;
                mp_find[{min(x, y), max(x, y)}] = num;
                if (num != x) {
                    pii p1 = {min(x, num), max(x, num)};
                    pii p2 = {min(y, num), max(y, num)};
                    if (st.find(p1) == st.end()) pq.push(p1);
                    if (st.find(p2) == st.end()) pq.push(p2);
                } else {
                    pii p1 = {min(x, y), max(x, y)};
                    if (st.find(p1) == st.end()) {
                        mp[x]++;
                        mp[y]++;
                        st.insert(p1);
                    }
                }
            }
        }
        cout << "! ";
        for (auto &[x, y] : st) cout << x << " " << y << " ";
        cout << endl;
        cout.flush();
    }
    return 0;
}

D. Longest Max Min Subsequence

题意

找最长的不存在重复元素的子序列并输出

要求有多个的话,按照奇数位乘 \(-1\) 的字典序输出

就是奇数位尽量大,偶数位尽量小

思路

获取子序列的长度很简单,用一个 \(map\),\(map\) 的 \(size\) 就是

假定子序列长度为 \(n\),先从简单的考虑,不考虑字典序的情况下,要判断一个位置能不能选中应该看当前位置及后面有多少可供选择的数

以样例 \([5,2,1,7,9,7,2,5,5,2]\) 为例,

第一次选择只能在前三个之间选,因为假定选了第四个数字 \(7\) ,后面不再有 \(1\) ,子序列最长只能到4

如果我们把 \(1\) 选了,那接下来我们可以在 \([5,2,\;,7,9]\) 之间选,但是又只能选1后面的数,所以就是79选其一

对于可供选择的区间,区间的左边界由于子序列的原因只能是不减的

区间的右边界由于子序列长度的原因,也是不减的

那么我们只要根据当前是奇数位还是偶数位,在可供选择的区间里选择最大或是最小值就行

就是双指针的思路,用[[multiset]]维护区间,一旦某个数字被选择了,就是删除set内的所有当前数字和当前数字之前的数字,然后再根据每个数字出现的最后位置更新一下set的右区间

代码

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

#define YES "Yes"
#define NO "No"
#define F first
#define S second
#define int long long
#define ull unsigned long long
#define endl "\n"
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
#define rep(i, j, k) for (int i = (j); i < (k); i++)
#define all(x) x.begin(), x.end()
#define vi vector<int>
#define pii pair<int, int>

const int N = 3e5 + 10;

signed main() {
    IOS;
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vi a(n);
        map<int, bool> vis;
        map<int, int> index;
        priority_queue<pii, vector<pii>, greater<pii>> Lx;// 存储每个数字出现的最后位置
        multiset<int> ms;
        rep(i, 0, n) {
            cin >> a[i];
            index[a[i]] = i;
        }

        for (auto &[x, in] : index) {
            vis[x] = false;
            Lx.push({in, x});
        }

        int len = index.size();
        cout << index.size() << endl;
        int be = 0;// begin
        int en = 0;// end
        int nlen = 0;
        int num = -1;
        while (nlen < len) {
            while (vis[Lx.top().S]) Lx.pop();

            for (int i = en; i <= Lx.top().F; i++) {
                if (!vis[a[i]])
                    ms.insert(a[i]);
            }

            en = Lx.top().F + 1;
            if (nlen % 2 == 0) {
                num = *ms.rbegin();
                cout << num << " ";
                vis[num] = 1;
                ms.erase(num);
                nlen++;
            } else {
                num = *ms.begin();
                cout << num << " ";
                vis[num] = 1;
                ms.erase(num);
                nlen++;
            }
            for (int i = be;; i++) {
                if (ms.find(a[i]) != ms.end())
                    ms.erase(ms.find(a[i]));
                if (a[i] == num) {
                    be = i + 1;
                    break;
                }
            }
        }
        cout << endl;
    }
    return 0;
}

标签:ABCD,967,int,cin,long,st,num,Div,define
From: https://www.cnblogs.com/lulaalu/p/18376107

相关文章

  • Codeforces Round 967 (Div. 2)-D
    CodeforcesRound967(Div.2)-D这些天在留校集训……我之前空余时间在看模电,最近在玩黑猴……九月开学了估计也不能闲下来……但这个博客我还是会抽空更新的╰(°▽°)╯Problem-D-Codeforces虽然代码写得特别丑陋,但好歹是我完全想的思路——自己还de了一天bug(゜ー゜)......
  • Codeforces Round 967 (Div. 2)
    题不难。A.MakeAllEqual题意:一个圆,上面有\(n\)个数,每次可以删去相邻的两个不同数中任意一个,求至少几次使得剩下的数都一样。显然下界是出现次数最多的数且一定能取到,时间复杂度\(O(n)\)。提交记录B.GeneratePermutation题意:要求构造一个排列,使得\(x\)所在位置大......
  • CF 2001 E2 solution (967 Div.2)
    CF2001E2由于对称,所以设\(heap[u]\)为两次确定堆,且第一次弹出的是\(u\),\(heap[u,v]\)是第一次\(u\),第二次\(v\)则答案就是\(\sumheap[u]=2^{n-1}·heap[x]\)其中\(x\)任意。不妨我们考虑第一次都是从第一个叶子弹出,那么对于其他不同的第二个弹出的点,根据对称性......
  • 题解:Codeforces Round 967 (Div. 2) B [思维/构造]
    B.GeneratePermutationtimelimitpertest:1.5secondsmemorylimitpertest:256megabytesinput:standardinputoutput:standardoutputThereisanintegersequence\(a\)oflength\(n\),whereeachelementisinitially\(-1\).Misukihastwoty......
  • Divisiblity of Difference
    题目传送门思路首先得知道个性质,即若$a\bmodb=c\bmodb$,那么$(a-c)\bmodb=0$,因为余数在$(a-c)$中被减掉了。于是我们可以把所有余数相同的$a_i$丢进一个vector里,之后再看余数相同的$a_i$的数量有没有$\gek$,有的话就输出前$k$个数,没有就输出No。代码#i......
  • Codeforces Round 966 (Div. 3)
    A.PrimaryTask#include<bits/stdc++.h>usingnamespacestd;usingvi=vector<int>;voidsolve(){strings;cin>>s;if(s.size()<=2){cout<<"NO\n";return;}if(s[0]!......
  • 题解:Codeforces Round 967 (Div. 2) [暴力/贪心]
    A.MakeAllEqualtimelimitpertest:1secondmemorylimitpertest:256megabytesinput:standardinputoutput:standardoutputYouaregivenacyclicarray\(a_1,a_2,\ldots,a_n\).Youcanperformthefollowingoperationon\(a\)atmost\(n-......
  • Codeforces Round 967 (Div. 2) C题 类分治解法
    废话不多说,先上代码t=int(input())whilet>0:n=int(input())pre_d={1:[iforiinrange(2,n+1)]}pair_l=[]whilelen(pre_d)!=0:item=pre_d.items()now_d={}fork,vinitem:forii......
  • Codeforces Round 967 (Div. 2)
    A.MakeAllEqual题意:给定n个数每次可以选2个相邻的数,并且前面的数不能比后面的数大,并且删除其中的一个。这个数组是循环数组,最后一个数是第一个数的前一个数。问最少操作多少次,可以让剩下的数全都相等。思路:红黑树+一次遍历,记录出现次数最多的数,剩下的数全部删掉即可。总结:看......
  • 【LGR-196-Div.4】洛谷入门赛 #26 题A - H 详细题解--优化思路简洁代码(C++,Python语
    前言:    觉得这个比赛很有意思的,都是暴力题,涉及一些细节,难度比较适合刚学编程语言的,可以很好的锻炼基础还有手速,最后两题也是比较有意思,之后也准备更新atc的比赛题解和洛谷的一些高质量比赛题解(算法网瘾就是想参加各种比赛)   如果觉得有帮助,或者觉得我写的好,......