1. 程式人生 > 其它 >Codeforces Round #772(Div.2) [A~D]

Codeforces Round #772(Div.2) [A~D]

連結:contest link

A.Min or Sum

題目

給定一個長度為 \(n\) 的陣列 \(a\) ,可以執行任意次如下操作:

  • 任取兩個整數 \(i,j\) ,使 \(a_i=x,a_j=y\)\(x,y\) 需要滿足 \(x\mid y=a_i\mid a_j\)

求執行操作後陣列元素和的最小值

分析

\(x=a_1\mid a_2\mid\cdots\mid a_n\)\(x\) 在執行操作的過程中是不變的

\(a_1\mid a_2\mid\cdots\mid a_n\leq a_1+a_2+\cdots+a_n\) ,所以元素和的最小值為 \(x\) ,考慮如何操作才能取到最小值,對於任意 \(i\in[1,n-1]\)

使 \(a_i=0,a_{i+1}=a_{i+1}\mid a_i\) 即可

程式碼

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

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin >> t;
    while(t--) {
        int n, a, res = 0;
        cin >> n;
        for(int i = 1; i <= n; i++) {
            cin >> a;
            res = res | a;
        }
        cout << res << endl;
    }
    return 0;
}

B.Avoid Local Maximums

題目

給定一個長度為 \(n\) 的陣列 \(a\) ,可以執行如下操作:

  • 任取一個整數 \(i\) ,使 \(a_i=x\)\(x\) 滿足 \(1\leq x\leq 10^9\)

求最少的運算元,使陣列不存在區域性最大值

區域性最大值的定義是:如果 \(a_{i-1}<a_i\)\(a_i>a_{i+1}\) 那麼 \(a_i\) 就是區域性最大值

分析

當我們找到一個區域性最大值 \(a_{i-1}\) 時,有 \(a_{i-2}<a_{i-1},a_{i-1}>a_i\) ,那麼我們可以修改 \(a_i\)

,當 \(a_{i-1}>a_{i+1}\) 時讓 \(a_i=a_{i-1}\) ,這樣 \(a_{i+1},a_{i-1}\) 就都不可能成為區域性最大值,當 \(a_{i-1}\leq a_{i+1}\) 時讓 \(a_i=a_{i+1}\) ,同樣,\(a_{i+1},a_{i-1}\) 都不可能成為區域性最大值。所以貪心策略是:\(a_{i-1}\) 為區域性最大值時使 \(a_i=\max(a_{i-1},a_{i+1})\)

程式碼

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

const int MAX_N = 200000 + 5;
int a[MAX_N];
int n;

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin >> t;
    while(t--) {
        cin >> n;
        for(int i = 1; i <= n; i++)
            cin >> a[i];
        a[n + 1] = 0;
        int cnt = 0;
        for(int i = 3; i <= n; i++) {
            if(a[i] < a[i - 1] && a[i - 1] > a[i - 2]) {
                a[i] = max(a[i - 1], a[i + 1]);
                cnt++;
            }
        }
        cout << cnt << endl;
        for(int i = 1; i <= n; i++)
            cout << a[i] << ' ';
        cout << endl;
    }
    return 0;
}

C.Differential Sorting

題目

給定一個長度為 \(n\) 的陣列 \(a\) ,可以執行如下操作:

  • 任取三個整數 \(x,y,z(1\leq x<y<z\leq n)\) ,使 \(a_x=a_y-a_z\)

求如何操作能使陣列變為非減序列,即 \(\forall i,a_i\leq a_{i+1}\)

不要求運算元最小

分析

考慮序列的最後三個數 \(a_n,a_{n-1},a_{n-2}\) ,由上述規則可知 \(a_{n-1}\)\(a_n\) 無法更改,如果 \(a_{n-1}>a_n\) ,那麼無論怎麼操作都不可能使序列非減

如果 \(a_{n-1}\leq a_n\)

  • \(a_n\geq 0\) 時我們可以遵循一個簡單的策略:\(i=n-2,n-3,\cdots 1\) 時依次執行操作 \((x,y,z)=(i,i+1,n)\) ,那麼 \(a_i=a_{i+1}-a_n\leq a_{i+1}\)
  • \(a_n<0\)\(a_{n-2}\) 只有在 \(a_{n-2}\leq a_{n-1}\) 才可保證序列非減,否則 \(a_{n-2}=a_{n-1}-a_n>a_{n-1}\) ,同理可推 \(a_{n-3},a_{n-4},\cdots a_1\) ,所以只有原序列滿足非減時才能進行 \(0\) 次操作,否則無論如何操作都不可能使序列非減

程式碼

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

const int MAX_N = 200000 + 5;
long long a[MAX_N];
int n;

struct node {
    int x, y, z;
} step[MAX_N];

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin >> t;
    while(t--) {
        cin >> n;
        for(int i = 1; i <= n; i++)
            cin >> a[i];
        if(a[n - 1] > a[n]) {
            cout << -1 << endl;
        } else {
            int cnt = 0;
            bool fnd = true;
            for(int i = n - 2; i >= 1; i--) {
                if(a[i] > a[i + 1]) {
                    if(a[n] >= 0) {
                        a[i] = a[i + 1] - a[n];
                        step[++cnt] = {i, i + 1, n};
                    } else {
                        fnd = false;
                        break;
                    }
                }
            }
            if(fnd) {
                cout << cnt << endl;
                for(int i = 1; i <= cnt; i++) 
                   cout << step[i].x << ' ' << step[i].y << ' ' << step[i].z << endl;
            } else {
                cout << -1 << endl;
            }
        }
    }
    return 0;
}

D.Infinite Set

題目

給定一個長度為 \(n\) 的陣列 \(a\) ,每個元素互不相同,設集合 \(S\) 為包含所有滿足以下條件的整數 \(x\)

  1. \(x=a_i\)
  2. \(x=2y+1\)\(y\in S\)
  3. \(x=4y\)\(y\in S\)

給定 \(p\) ,求 \(S\) 中小於 \(2^p\) 的元素個數

分析

參考官方題解,推理自然簡明:tutorial

程式碼

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

const int MAX_N = 200000 + 5;
const int MOD = 1e9 + 7;
int n, p, ans = 0;
int a[MAX_N], f[MAX_N], cnt[MAX_N];
set<int> useful;

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> p;
    for(int i = 1; i <= n; i++)
        cin >> a[i];
    sort(a + 1, a + n + 1);
    for(int i = 1; i <= n; i++) {
        int x = a[i];
        bool flag = false;
        while(x > 0) {
            if(useful.count(x)) {
                flag = true;
                break;
            }
            if(x % 2)
                x /= 2;
            else if(x % 4 == 0)
                x /= 4;
            else
                break;
        }
        if(!flag)
            useful.insert(a[i]);
    }
    for(int x : useful)
        cnt[__lg(x)]++;
    for(int i = 0; i < p; i++) {
        f[i] = cnt[i];
        if(i >= 1)
            f[i] = (f[i] + f[i - 1]) % MOD;
        if(i >= 2)
            f[i] = (f[i] + f[i - 2]) % MOD;
        ans = (ans + f[i]) % MOD;
    }
    cout << ans << endl;
    return 0;
}