Codeforces Round #669 (Div. 2) A - D 解题报告

题目链接


A. Ahahahahahahahaha

题意:

给定长度为 \(n\)\(0, 1\) 数组,\(n\) 为偶数,你最多可以删去 \(\frac{n}{2}\) 个数,使得结果数组的奇数位和等于偶数位和,输出结果数组。

思路:

计算出 \(0\)\(1\) 的个数,谁多就输出谁。

注:\(1\) 多的情况要判断奇偶。

代码:
/*
 * @Author       : nonameless
 * @Date         : 2020-09-08 22:22:23
 * @LastEditors  : nonameless
 * @LastEditTime : 2020-09-08 22:52:09
 */
#include <bits/stdc++.h>
#define x first
#define y second
#define pb push_back
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()
using namespace std;
typedef long long ll;
typedef pair<ll, ll> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
const double eps = 1e-6;
const double PI  = acos(-1.0);
const int INF = 0x3f3f3f3f;
const ll LNF  = 0x3f3f3f3f3f3f;
inline int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
inline ll  gcd(ll  a, ll  b) { return b ? gcd(b, a % b) : a; }
inline int lcm(int a, int b) { return a * b / gcd(a, b); }

const int N = 1e3 + 10;

int a[N];

int main(){

    int t; cin >> t;
    while(t --){
        int n; cin >> n;
        for(int i = 1; i <= n; i ++) scanf("%d", a + i);
        int x = n >> 1;
        int one = 0, zero = 0;
        for(int i = 1; i <= n; i ++)
            if(a[i] == 1) one ++;
            else zero ++;
        if(one > x){
            if(one & 1) one --;
            cout << one << endl;
            for(int i = 1; i <= one; i ++) printf("1 ");
            puts("");
        } else{
            cout << zero << endl;
            for(int i = 1; i <= zero; i ++) printf("0 ");
            puts("");
        }
        
    }
    
    return 0;
}


B. Big Vova

题意:

给定一个序列 \(a\),序列 \(b\)\(a\) 的一个排列,定义 \(c_i = gcd(b_1,...,b_i)\)

要求求得的 \(c\) 的字典序最大,求序列 \(b\)

思路:

看数据范围就可以知道直接暴力即可。

首先很明显的是 \(b_1 = max(a_1,a_2,...,a_n)\),根据这个找下去即可。

代码:
/*
 * @Author       : nonameless
 * @Date         : 2020-09-08 22:59:37
 * @LastEditors  : nonameless
 * @LastEditTime : 2020-09-08 23:24:08
 */
#include <bits/stdc++.h>
#define x first
#define y second
#define pb push_back
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()
using namespace std;
typedef long long ll;
typedef pair<ll, ll> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
const double eps = 1e-6;
const double PI  = acos(-1.0);
const int INF = 0x3f3f3f3f;
const ll LNF  = 0x3f3f3f3f3f3f;
inline int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
inline ll  gcd(ll  a, ll  b) { return b ? gcd(b, a % b) : a; }
inline int lcm(int a, int b) { return a * b / gcd(a, b); }

const int N = 1e3 + 10;

int a[N], b[N];

map<int, int> mp;

int main(){

    int t; cin >> t;
    while(t --){
        int n; cin >> n;
        
        for(int i = 1; i <= n; i ++) scanf("%d", a + i);
        for(int i = 1; i <= n; i ++) mp[a[i]] ++;
        b[1] = *max_element(a + 1, a + n + 1);
        
        int idx = 1;
        int x = b[1];
        mp[b[1]]--;
        while(idx < n){
            int tmp = 1, val;
            for(int i = 1; i <= n; i ++){
                if(mp[a[i]]){
                    if(gcd(x, a[i]) > tmp){
                        tmp = gcd(x, a[i]);
                        val = a[i];
                    }
                }
            }
            if(tmp == 1) break;
            b[++idx] = val;
            mp[val] --;
            x = tmp;
        }

        if(idx < n){
            for(int i = 1; i <= n; i ++){
                if(mp[a[i]]) b[++idx] = a[i];
            }
        }

        
        for(int i = 1; i <= n; i ++) printf("%d ", b[i]);
        puts("");

        mp.clear();
    }
    return 0;
}


C. Chocolate Bunny

题意:

交互题。

求一个未知的全排列 \(a\)

可以询问 \(2\times n\) 次,每次给出两个不同的索引 \(i\)\(j\),会返回 \(a_i \% a_j\) 的值。

思路:

询问 \(i, j\),我们假设 \(a_i < a_j\)

显然 \(a_i \% a_j = x = a_i\)

再询问 \(j, i\):

显然 \(a_j \% a_i = y < a_i\)

那么我们显然 \(a_i = max(x, y)\)

每询问两次可以确定一个位置的值,符合要求。

代码:
/*
 * @Author       : nonameless
 * @Date         : 2020-09-08 23:25:35
 * @LastEditors  : nonameless
 * @LastEditTime : 2020-09-08 23:45:28
 */
#include <bits/stdc++.h>
#define x first
#define y second
#define pb push_back
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()
using namespace std;
typedef long long ll;
typedef pair<ll, ll> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
const double eps = 1e-6;
const double PI  = acos(-1.0);
const int INF = 0x3f3f3f3f;
const ll LNF  = 0x3f3f3f3f3f3f;
inline int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
inline ll  gcd(ll  a, ll  b) { return b ? gcd(b, a % b) : a; }
inline int lcm(int a, int b) { return a * b / gcd(a, b); }

const int N = 1e4 + 10;

int arr[N];

int main(){

    int n; cin >> n;

    if(n == 1) puts("! 1");
    else{
        map<int, int> mp;
        int x = 1;
        int a, b;
        for(int i = 2; i <= n; i ++){
            cout << "? " << x << " " << i << endl;
            cin >> a;
            cout << "? " << i << " " << x << endl;
            cin >> b;
            if(a < b){
                arr[i] = b;
                mp[b] = 1;
            } else{
                arr[x] = a;
                mp[a] = 1;
                x = i;
            }
        }
        for(int i = 1; i <= n; i ++){
            if(mp[i] == 1) continue;
            arr[x] = i;
            break;
        }
        cout << "!";
        for(int i = 1; i <= n; i ++) cout << " " << arr[i];
        puts("");
    }
    
    return 0;
}


D. Discrete Centrifugal Jumps

题意:

\(n\) 个柱子,第 \(i\) 个柱子的高度为 \(h_i\),你满足以下条件之一就可以从 \(i\) 跳到 \(j\)

  • \(j = i + 1\)
  • \(max(h_{i+1},...,h_{j-1}) < min(h_i, h_j)\)
  • \(max(h_i, h_j) < min(h_{i+1},...,h_{j-1})\)

问从第一个柱子跳到第 \(n\) 个柱子的最小步数?

思路:

考虑线性 \(dp\),设 \(f[i]\):跳到第 \(i\) 个柱子的最小步数

转移方程:\(f[j] = min(f[j], f[i] + 1)\)(如果 \(i\) 可以跳到 \(j\) )。

第一种情况不做考虑,此时我们只考虑第二种情况,第三种类似。

对于 \(i\) 来说,\(j\) 就是大于等于他,且离他最近的那个柱子(\(i < j\)),那么此时 \(i\) 可以跳到 \(j\),显然这个性质可以单调栈来解决。

不理解代码的可以用这组样例来理解第二种情况:\(4,3, 2, 1, 5\).

注:

  • 单调递增栈:从栈顶到栈底递增
  • 单调递减栈:从栈顶到栈底递减
代码:
/*
 * @Author       : nonameless
 * @Date         : 2020-09-09 15:10:43
 * @LastEditors  : nonameless
 * @LastEditTime : 2020-09-09 15:37:44
 */
#include <bits/stdc++.h>
#define x first
#define y second
#define pb push_back
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()
using namespace std;
typedef long long ll;
typedef pair<ll, ll> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
const double eps = 1e-6;
const double PI  = acos(-1.0);
const int INF = 0x3f3f3f3f;
const ll LNF  = 0x3f3f3f3f3f3f;
inline int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
inline ll  gcd(ll  a, ll  b) { return b ? gcd(b, a % b) : a; }
inline int lcm(int a, int b) { return a * b / gcd(a, b); }

const int N = 3e5 + 10;

int h[N], f[N];

stack<int> in, de;

int main(){

    int n; cin >> n;

    memset(f, INF, sizeof f);
    f[1] = 0;

    auto update = [&](stack<int> &s, int idx){
        if(!s.empty()){
            f[idx] = min(f[idx], f[s.top()] + 1);
            if(h[s.top()] == h[idx]) s.pop();
        }
        s.push(idx);
    };

    for(int i = 1; i <= n; i ++){
        scanf("%d", h + i);
        while(!de.empty() && h[i] < h[de.top()]){ // 单调递减栈 对应第三种情况
            f[i] = min(f[i], f[de.top()] + 1);
            de.pop();
        }
        update(de, i);
        while(!in.empty() && h[i] > h[in.top()]){ // 单调递增栈 对应第二种情况
            f[i] = min(f[i], f[in.top()] + 1);
            in.pop();
        }
        update(in, i);
    }

    cout << f[n] << endl;
    
    return 0;
}
posted @ 2020-09-09 01:32  nonameless  阅读(194)  评论(4编辑  收藏  举报