0
点赞
收藏
分享

微信扫一扫

Codeforces Round #772 (Div. 2) ABCD

闲云困兽 2022-02-21 阅读 35

A - Min Or Sum

根据题目要求可以发现,要使得总和尽可能地小,应尽可能将选择的 ( a i , a j ) (a_i, a_j) (ai,aj)变为 ( a i ∣ a j , 0 ) (a_i | a_j, 0) (aiaj,0)。那么统计 1 1 1的位数求和或直接所有元素求或即可。

#include <bits/stdc++.h>
#define int long long

inline void solve(){
    int ans = 0, n = 0; std::cin >> n;
    for(int i = 1; i <= n; i++){
        int x; std::cin >> x;
        ans |= x;
    }
    std::cout << ans << std::endl;
}

signed main(){
    int t = 0; std::cin >> t;
    while(t--) solve();
    return 0;
}

B - Avoid Local Maximums

扫描序列,每当发现一个local minium就将其替换为两侧数字较大的一个(或者直接按照单增贪心修改)。这样可以保证单向单调性。

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

const int N = 2e5 + 10;
int a[N], book[N];

inline void solve(){
    int n = 0, cnt = 0; cin >> n;
    memset(book, 0, sizeof book);
    for(int i = 1; i <= n; i++) cin >> a[i];
    for(int i = 2; i < n; i++){
        if(a[i] > a[i - 1] && a[i] > a[i + 1]){
            a[i] = max(a[i + 1], a[i + 2]);
            cnt++;
        }
    }
    cout << cnt << endl;
    for(int i = 1; i <= n; i++){
        cout << a[i] << ' ';
    }
    cout << endl;
}

signed main(){
    int t = 0; cin >> t;
    while(t--) solve();
    return 0;
}

C - Differential Sorting

每次可以选择 1 ≤ x ≤ y ≤ z ≤ n 1 \leq x \leq y \leq z \leq n 1xyzn,然后令 a x = a y − a z a_x = a_y - a_z ax=ayaz。通过有限次操作令序列有序(不递减)。

首先考虑非法情况:

  • 如果 a n − 1 ≥ a n a_{n - 1} \geq a_n an1an,那么无法将 a n − 1 a_{n - 1} an1元素修改为更小的元素,此时非法
  • 如果 a n < 0 a_n < 0 an<0,如果序列未排序,那么为了将序列修改为不递减,我们应该将整个序列修改为 a n − 1 − a n a_{n - 1} - a_n an1an。此时由于 a n < 0 a_n < 0 an<0,那么无法满足不递减的条件。

判读非法情况,然后输出即可。

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

const int N = 4e5 + 10;
int a[N];

inline void solve(){
    int n = 0; cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];
    if(is_sorted(a + 1, a + 1 + n)) cout << 0 << endl;
    else if(a[n] < a[n - 1] || a[n] < 0) puts("-1");
    else{
        cout << n - 2 << endl;
        for(int i = 1; i <= n - 2; i++) cout << i << ' ' << n - 1 << ' ' << n << endl;
    }
}

signed main(){
    int t = 0; cin >> t;
    while(t--) solve();
    return 0;
}

D - Infinite Set

构造集合 S S S,使满足任一条件:

  • x ∈ S , x ∈ a i x \in S, x \in {a_i} xS,xai
  • x ∈ S , y = 2 x + 1 ∈ S x \in S, y = 2x + 1 \in S xS,y=2x+1S
  • x ∈ s , y = 4 x ∈ S x \in s, y = 4x \in S xs,y=4xS

求集合中小于 2 p 2^p 2p的元素的个数。

首先考虑 a a a序列只有一个元素的情况:

y = 2 x + 1 y = 2x + 1 y=2x+1 y = 4 x y = 4x y=4x有很明显的区别:前者是左移 1 1 1 + 1 +1 +1,后者是左移两位。每次可以生成两个数字。我们反过来考虑,一个数字可以由两种情况转移而来:设数字的长度为 l l l,则长度为 l − 1 l - 1 l1和长度 l − 2 l - 2 l2的两个可以转移得到。

如果推广到多个元素的状态,那么只需要预处理出各个起始长度的值(这里需要去重),然后计数即可。

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


const int N = 2e5 + 10, MOD = 1e9 + 7;
int a[N], dp[N];
set<int> st;

inline void solve(){
    st.clear();
    int n = 0, ans = 0, p = 0; cin >> n >> p;
    for(int i = 1; i <= n; i++) cin >> a[i];
    auto countx = [&](int x, int ans = 0){ while((1 << ans) <= x) ans++; return ans; };
    sort(a + 1, a + 1 + n);
    for(int i = 1; i <= n; i++){
        int x = a[i];
        //找到最初的数并判重
        while(x != 1){
            if(st.count(x)) break;
            if(x % 4 == 0) x >>= 2;
            else if(x & 1) x >>= 1;
            else break;
        }
        if(st.count(x)) continue;
        st.insert(a[i]);
        dp[countx(a[i])]++;
    }
    for(int i = 2; i <= p; i++) dp[i] = (dp[i] + dp[i - 1] + dp[i - 2]) % MOD;
    for(int i = 1; i <= p; i++) (ans += dp[i]) %= MOD;
    cout << ans << endl;
}

signed main(){
    //int t = 0; cin >> t;
    //while(t--) 
    solve();
    return 0;
}
举报

相关推荐

0 条评论