Codeforces Round #808 (Div. 2) A-D

Codeforces Round #808 (Div. 2)

https://codeforces.com/contest/1708

被虐惨了(爆哭...

A. Difference Operations

题意

对于任意一个 \(2\leq i\leq n\),可以把 \(a_i\) 变成\(a_{i-1}\),求能否经过若干操作,使得 \(a_i=0,2\leq i\leq n\)

分析

上述操作暗含一种"传递"的思想,即可以从第一项传递到后面。所以能否变为全0就看 是否所有的数都为a[1]的倍数

十分不严谨的证明:
若存在 \(a_k\),不为 \(a_1\) 的倍数,而\(a_1,a_2,...,a_{k-1}\) 皆为 \(a_1\) 的倍数,那么这些数必然能最终转化为0,最后只剩一个 \(a_k\) 没法消掉。

故所有数都要是 \(a_1\) 的倍数才行

Code

#include <bits/stdc++.h>

using namespace std;
const int N = 105;
int a[N], n;

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

    for (int i = 1; i <= n; i ++)   cin >> a[i];
    for (int i = 2; i <= n; i ++) {
        if (a[i] % a[1]) {
            cout << "NO\n";
            return ;
        }
    }
    cout << "YES\n";
}

int main () {
    int t;
    cin >> t;
    while (t --) {
        solve ();
    }
}

//都能整除1就ok

B. Difference of GCDs

题意

给定区间 \([l,r]\),试构造n项数列 \(a_i,(l\leq a_i\leq r)\),使得每一项 \(gcd(i,a_i)\) 都不同

分析

第一想法是构造 i 的倍数,因为每一个 i 是不同的,按照其倍数来构造就能够使得 gcd 在每一项都不同

关于如何找倍数:

暴力找是会超时的,所以我们就要用到————
结论:区间 \([l,r]\) 内 x 的最小倍数为 \(\lceil \frac lx \rceil \times x\),然后再判断该数字是否在区间内即可

Code

#include <bits/stdc++.h>

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

void solve () {
    int n, l, r;
    cin >> n >> l >> r;

    vector <int> v;
    for (int i = 1; i <= n; i ++) {
        bool suc = false;

        int x = (int)ceil(1.0*l/i)*i;
        if (x >= l && x <= r) {
            v.push_back (x);
        }
        
        else {
            cout << "NO\n";
            return ;
        }
        
    }
    
    cout << "YES\n";
    for (auto i : v)    cout << i << ' ';
    cout << endl;
    
}

int main () {
    int t;
    cin >> t;
    while (t --) {
        solve ();
    }
}
//gcd(i, ai)全不同
//构造i的倍数即可

C. Doremy's IQ

题意

现有智商q 和 n 个难度的问题,对于任意难度值为 \(a_i\) 的问题:

可以选择挑战(必须保证此时 q > 0)或不挑战

  1. 选择挑战 \(a_i>q\),的问题则会消耗一点 q
  2. 选择挑战 \(a_i\leq q\),的问题则 q 不变

分析

贪心:对于不能取的,如果不影响后面一整段的选取,那么可以拿走
因为对于需要 q-- 的选取,无论如何都要减少,那么放在后面一定更优 (对于后续影响更少)

所以预处理每一个点取掉所需的 q 值即可

Code

#include <bits/stdc++.h>

using namespace std;
const int N = 1e5 + 5;
int n, q;
int a[N], s[N];//难度 所需q 

void solve () {
    cin >> n >> q;
    vector <int> b(n+1, 0);
    for (int i = 1; i <= n; i ++) 
        cin >> a[i];
    s[n] = 1;
    //预处理需求
    for (int i = n - 1; i >= 1; i --) {
        if (a[i] <= s[i+1])  s[i] = s[i+1];
        else    s[i] = s[i+1] + 1;
    }

    for (int i = 1; i <= n; i ++) {
        if (q >= s[i]) {
            for (int j = i; j <= n; j ++)
                b[j] = 1; //后面一整段都选
            break;
        }
        if (q >= a[i])  b[i] = 1;
    }
    
    for (int i = 1; i <= n; i ++) 
        cout << b[i];
    cout << endl;
}

int main () {
    int t;
    cin >> t;
    while (t --)    solve ();
}

//贪心
//优先取了不用--的
//1后面添0,不够了再往前凑
//记录最末尾的1

//对于不能取的,如果不影响后面一整段的选取,那么可以拿走

D. Difference Array

题意

对于一个(已经从小到大排好序的)序列a, 每次都求其相邻两项之差,然后再从小到大排序 ... 如此反复 n-1 次,求最后剩下的数是多少

分析

这样的操作下,数列减的速度是非常快的,也就是说,易出现很多的0,0的操作没啥意义,所以我们要找到第一个 >0 的数对其后的序列进行排序,就能大大减少复杂度

Code

#include <bits/stdc++.h>

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

void solve () {
    cin >> n;
    for (int i = 1; i <= n; i ++)   cin >> a[i];
    //priority_queue <int, vector<int>, greater<int>> q, p;
    int pos;
    for (int i = 1; i <= n; i ++) {
        if (a[i]) {
            pos = i - 1;
            break;
        }
    }
    while (n > 1) {
        for (int i = max(1, pos); i < n; i ++)
            a[i] = a[i+1] - a[i];
        n --;
        
        sort (a + pos, a + n + 1);
        pos = upper_bound (a + 1, a + n + 1, 0) - (a + 1);
        //pos --;
        if (pos == n - 1)   break;
    }    
    cout << a[n] << endl;
}

int main () {
    int t;
    cin >> t;
    while (t --) {
        solve ();
    }
}

//二分
posted @ 2022-07-17 08:48  Sakana~  阅读(57)  评论(0编辑  收藏  举报