Codeforces Round 960 (Div. 2)(ABCD)

C o d e f o r c e s R o u n d 960 ( D i v . 2 ) \Huge{ Codeforces Round 960 (Div. 2)} CodeforcesRound960(Div.2)


题目链接:Codeforces Round 960 (Div. 2)

Problems A. Submission Bait

题意

给出一个数组,Alice和Bob每次可以选择一个数字,且每次选择的数字不小于上一个人选择的数字。然后将其变为0。

最后无法进行选择的人输掉比赛。

思路

Alice先手,若最大数的个数为奇数,那么Alice赢,若为偶数,考虑第二大数字的个数,以此类推。

标程

#include<bits/stdc++.h>

using namespace std;
void Solved() {
    int n; cin >> n;
    vector<int> a(n + 1);

    for(int i = 1; i <= n; i ++ ) cin >> a[i];
    
    sort(a.begin() + 1, a.end(), [](int n1, int n2) {
        return n1 > n2;
    });

    int x = 0, mx = a[1], z = 1;
    for(int i = 1; i <= n;  i ++ ) {
        if(mx == a[i]) x ++;
        else {
            if(x % 2 == z) {
                cout << "YES\n"; return;
            } else {
                x = 1; mx = a[i];
            }
        }
    }

    if(x % 2 == z) cout << "YES\n";
    else cout << "NO\n"; 
}

signed main(void) {
    int ALL = 1; 
    cin >> ALL;
    while(ALL -- ) Solved();

    return 0;
}

Problems B. Array Craft

题意

给出数组b,然后给出两个定义:

  1. 最大前缀位置:满足 b 1 + … + b i = max ⁡ j = 1 m ( b 1 + … + b j ) b_1+\ldots+b_i=\max_{j=1}^{m}(b_1+\ldots+b_j) b1++bi=maxj=1m(b1++bj)的最小索引 i i i
  2. 最大后缀位置:满足 b i + … + b m = max ⁡ j = 1 m ( b j + … + b m ) b_i+\ldots+b_m=\max_{j=1}^{m}(b_j+\ldots+b_m) bi++bm=j=1maxm(bj++bm)的最小索引 i i i

然后给出三个整数 n , x , y n,x,y n,x,y,分别表示数组大小,最大前缀位置,最大后缀位置。

思路

根据 x , y x,y x,y的相对位置直接模拟就行。

根据定义, a X = a y = 1 a_X=a_y=1 aX=ay=1,对于 x x x,从 x x x开始的 ( 1 ≤ i ≤ x ) (1\le i \le x) (1ix)的前缀和必然大于 1 1 1,从 x x x开始的 ( x ≤ i ≤ n ) (x\le i \le n) (xin)的前缀和必然小于 1 1 1 y y y也同理。

标程

#include<bits/stdc++.h>

using namespace std;

void Solved() {
    int n, x, y; cin >> n >> x >> y;

    vector<int> a(n + 1);

    a[x] = a[y] = 1;
    if(x <= y) {
        int x1 = 0;
        for(int i = x; i >= 1; i -- ) {
            if(x1 < 1) a[i] = 1, x1 ++;
            else a[i] = -1, x1 --;
        }
        for(int i = x + 1; i < y; i ++ ) {
            a[i] = -1;
        }
        x1 = 0;
        for(int i = y; i <= n; i ++ ) {
            if(x1 < 1) a[i] = 1, x1 ++;
            else a[i] = -1, x1 --;
        }
    } else {
        int x1 = 1;
        for(int i = y - 1; i >= 1; i -- ) {
            if(x1 >= 1) a[i] = -1, x1 --;
            else a[i] = 1, x1 ++;
        }
        for(int i = y + 1; i < x; i ++ ) {
            a[i] = 1;
        }
        x1 = 1;
        for(int i = x + 1; i <= n; i ++ ) {
            if(x1 >= 1) a[i] = -1, x1 --;
            else a[i] = 1, x1 ++;
        }
    }

    for(int  i= 1 ; i <= n; i ++ ) {
        cout << a[i] << ' ';
    } cout << endl;
}

signed main(void) {
    int ALL = 1; 
    cin >> ALL;
    while(ALL -- ) Solved();

    return 0;
}

Problems C. Mad MAD Sum

题意

给出定义: M A D MAD MAD(最大显示重复数)在数组中出现至少两次的最大数。具体来说,如果没有出现至少两次的数字,则 M A D MAD MAD 0 0 0

循环执行下列操作:

  1. s u m = s u m + ∑ i = 1 n a i sum=sum+\sum_{i=1}^{n}{a_i} sum=sum+i=1nai
  2. b i = M A D ( a 1 , a 2 … a n ) b_i=MAD(a_1,a_2…a_n) bi=MAD(a1,a2an)
  3. a i = b i ( 1 ≤ i ≤ n ) a_i=b_i(1\le i \le n) ai=bi(1in)

当数组 a a a全为0时结束循环,求sum的大小。

思路

手动模拟一次即可发现,只需一次循环,数组a就会变为不严格的升序 a i ≤ a i + 1 ( 1 ≤ i ≤ n − 1 ) a_i\le a_{i + 1}(1\le i\le n-1) aiai+1(1in1)

设第一次手动模拟后的数组为b_1,那么b_1中除了最后一位,其他位可能会出现单个数字的情况(即相邻两个数都不同),且现在b_i为升序,那么这一位在下一次循环后就不存在了。

但第二次循环之后,b_2除最后一位,其他位不可能出现上述情况。

b_1之所以会出现单个数字的情况,是因为循环前原数组可能是无序的。

b_2不会出现这种情况就是因为b_1是有序的。

规律可以观察下列两种情况:

a : [ 4 , 5 , 3 , 3 , 3 , 3 , 4 , 5 ] a:[4,5,3,3,3,3,4,5] a:[4,5,3,3,3,3,4,5] a : [ 4 , 4 , 5 , 5 , 6 , 6 ] a:[4,4,5,5,6,6] a:[4,4,5,5,6,6]
b 1 : [ 0 , 0 , 0 , 3 , 3 , 3 , 4 , 5 ] b_1:[0,0,0,3,3,3,4,5] b1:[0,0,0,3,3,3,4,5] b 1 : [ 0 , 4 , 4 , 5 , 5 , 6 ] b_1:[0,4,4,5,5,6] b1:[0,4,4,5,5,6]
b 2 : [ 0 , 0 , 0 , 0 , 3 , 3 , 3 , 3 ] b_2:[0,0,0,0,3,3,3,3] b2:[0,0,0,0,3,3,3,3] b 2 : [ 0 , 0 , 4 , 4 , 5 , 5 ] b_2:[0,0,4,4,5,5] b2:[0,0,4,4,5,5]
b 3 : [ 0 , 0 , 0 , 0 , 0 , 3 , 3 , 3 ] b_3:[0,0,0,0,0,3,3,3] b3:[0,0,0,0,0,3,3,3] b 3 : [ 0 , 0 , 0 , 4 , 4 , 5 ] b_3:[0,0,0,4,4,5] b3:[0,0,0,4,4,5]
b 4 : [ 0 , 0 , 0 , 0 , 0 , 0 , 3 , 3 ] b_4:[0,0,0,0,0,0,3,3] b4:[0,0,0,0,0,0,3,3] b 4 : [ 0 , 0 , 0 , 0 , 4 , 4 ] b_4:[0,0,0,0,4,4] b4:[0,0,0,0,4,4]
b 5 : [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 3 ] b_5:[0,0,0,0,0,0,0,3] b5:[0,0,0,0,0,0,0,3] b 5 : [ 0 , 0 , 0 , 0 , 0 , 4 ] b_5:[0,0,0,0,0,4] b5:[0,0,0,0,0,4]

通过规律,我们可以先处理出来前两次循环,然后直接计算即可

标程

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

#define int long long 

void Solved() {
    int n; cin >> n;
    vector<int> a(n + 1);

    for(int i = 1; i <= n; i ++ ) cin >> a[i];

    int mx = 0, res = 0;
    for(int j = 0; j < 2; j ++ ) {
        map<int, int> mp;
        mx = 0;
        for(int i = 1; i <= n; i ++ ) {
            res += a[i];
            mp[a[i]] ++;
            if(mp[a[i]] >= 2) mx = max(mx, a[i]);
            a[i] = mx;
        }
    }
    for(int i = 1; i <= n; i ++ ) {
        res += a[i] * (n - i + 1);
    }
    
    cout << res<< endl;    
}

signed main(void) {
    int ALL = 1; 
    cin >> ALL;
    while(ALL -- ) Solved();

    return 0;
}

Problems D. Grid Puzzle

题意

给出一个数字n,然后给出一个长度为 n n n的数组 a a a。数组a表示在一个大小为 n × n n\times n n×n的矩阵中,第i行的前 a i a_i ai各元素是黑色。

先有下列两种操作,每次只能选择一个执行:

  1. 选择一个 2 × 2 2\times 2 2×2的矩阵,并将其变为白色。
  2. 选择任意一行,将其全变为白色。

问最少操作多少次,可以将整个 n × n n\times n n×n的矩阵全变为白色。

思路

  1. 容易发现,如果当前行 a i > 4 a_i > 4 ai>4,那么显然使用一次操作2最优。

  2. 如果相邻两行 a i ≤ 2 a_i \le 2 ai2,那么使用操作1最优,因为可能消除下一行。

  3. 如果当前的 a i ≤ 4 a_i\le 4 ai4,那么可能用操作1,也可能是操作2;此时若下一行 a i + 1 ≤ 4 a_{i+1}\le 4 ai+14,那么考虑当前使用操作1。

综上,我们可以用 f i f_i fi表示前i行的最优解, g i g_i gi记录上述(3)的情况,然后进行状态转移即可。最后 f [ n ] f[n] f[n]即为结果。

标程

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

const int mod = 1e9 + 7;

void Solved() {
    int n; cin >> n;
    vector<int> a(n + 1), f(n + 1), g(n + 1, mod);;

    int res = 0;
    for(int i = 1; i <= n; i ++ ) cin >> a[i];
    
    for(int i = 1; i <= n; i ++ ) {
        f[i] = f[i - 1] + (a[i] > 0);                   //默认都用操作2
        if(a[i] <= 2) {                                 //这类情况可以判断是否用操作1
            g[i] = min(g[i], f[i - 1] + 1);
            f[i] = min(f[i], g[i - 1]);					//考虑将上一行的染色方式改为操作1
        }
        if(i + 1 <= n && a[i] <= 4 && a[i + 1] <= 4) {  //这类情况用两次操作1最优
            g[i + 1] = g[i - 1] + 2;
        }
    }
    
    cout << f[n]<< endl;
}

signed main(void) {
    int ALL = 1; 
    cin >> ALL;
    while(ALL -- ) Solved();

    return 0;
}
  • 16
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值