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;
}
posted @ 2022-03-16 21:32  f(k(t))  阅读(35)  评论(0编辑  收藏  举报