Deltix Round, Summer 2021 Div. 1 + Div. 2 A B C D

Posted a碟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Deltix Round, Summer 2021 Div. 1 + Div. 2 A B C D相关的知识,希望对你有一定的参考价值。

A. A Variety of Operations

题目链接

题意:
给定两个数 a , b a,b a,b,初始值为 0 0 0,有三个操作, a a a b b b都加 k k k;或者 a a a k k k, b b b k k k;或者 b b b k k k, a a a k k k。问最少执行多少次操作,使得 a = c , b = d a=c,b=d a=c,b=d。无法完成则输出 − 1 -1 1

分析:
因为在任意变化之后, a − b a-b ab奇偶性是不会发生变化的,因为初始 a , b a,b a,b都是 0 0 0 a − b = 0 a-b=0 ab=0。所以如果 c − d c-d cd的差是奇数,则不可能得到这个数对。
而如果 c − d c-d cd的差是偶数,又要分几种情况讨论

  • 如果 c = 0 c=0 c=0 d = 0 d=0 d=0,那么不需要操作,输出 0 0 0
  • 如果 c = d c=d c=d且不等于 0 0 0,那么需要操作 1 1 1
  • 其他情况需要操作 2 2 2次,我们可以使用第二种类型或第三种类型的运算 k = ∣ c − d ∣ 2 k=\\frac {|c−d|}{2} k=2cd。如果 c > d c>d c>d则使用第二种, c < d c<d c<d使用第三种。在此之后,假设 c > d c>d c>d,再使用第一种类型的操作, k = c − ∣ c − d ∣ 2 k=c-\\frac {|c−d|}{2} k=c2cd c < d c<d c<d同理。

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;

int main()
{
    int t;scanf("%d",&t);
    while(t--){
        int c,d;scanf("%d %d",&c,&d);
        if(c==0&&d==0)printf("0\\n");
        else if((c-d)%2)printf("-1\\n");
        else if(c==d)printf("1\\n");
        else printf("2\\n");
    }
    return 0;
}

B. Take Your Places!

题目链接

题意:
给定一个数组 a a a,每一次可以交换相邻的两个元素,问最少交换多少次使得整个元素每两个相邻元素之间的奇偶性不同,也就是整个数组是奇偶交替的。

分析:
贪心,贪心思路对了就很好想了。首先,判断无法成立很容易,如果是偶数个元素,判断是否奇偶数各占一半,如果是奇数个元素,判断是否奇数比偶数多 1 1 1或者少 1 1 1。如果无法成立,则输出 − 1 -1 1
否则,我们只需要考虑两种情况

  • 第一个元素是奇数。
  • 第一个元素是偶数。

也就是说,我们最后的数组一定是 10101 10101 10101,或者 01010 01010 01010这样的( 1 1 1看成奇数, 0 0 0看成偶数)。我们可以将当前数组的奇数位置存储下来,如果数组总个数 n n n为奇数,那么如果奇数多就将奇数放在奇数位置奇数少就将奇数放在偶数位置,依次放入,暴力求移动次数。如果数组总个数 n n n为偶数,那么奇数放在奇数位置算一次,奇数放在偶数位置也算一次移动次数,取 m i n min min即可。

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#define ll long long
using namespace std;
const int N=1e5+5;
int a[N],temp[N];
int main()
{
    int t;scanf("%d",&t);
    while(t--){
        int n;scanf("%d",&n);
        vector<int>odd;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            if(a[i]%2)odd.push_back(i);
        }
        if((odd.size()*2!=n&&n%2==0)||(odd.size()*2!=n-1&&odd.size()*2!=n+1&&n%2==1)){
            puts("-1");
            continue;
        }
        int k=1,res=0,cnt=0;
        if(n%2==0){
            for(auto x:odd){
                res+=abs(x-k);k+=2;
            }
            k=2;
            for(auto x:odd){
                cnt+=abs(x-k);k+=2;
            }
        }
        else{
            if(odd.size()*2==n-1)k=2;
            else k=1;
            for(auto x:odd){
                res+=abs(x-k);k+=2;
            }cnt=res;
        }
        printf("%d\\n",min(res,cnt));
    }
    return 0;
}

C. Compressed Bracket Sequence

题目链接

题意:
给定一个括号序列,这个括号序列是给的每一次连续的括号的数量,第 i i i个位置,如果 i i i是奇数,则给定的是 ′ ( ′ '(' (的括号数量,如果i是偶数,则给定的是 ′ ) ′ ')' )的括号数量。例如,对于括号序列 “ ( ( ) ) ( ) ) ” “(())())” (())()),相应的数字序列是 [ 3 , 2 , 1 , 3 ] [3,2,1,3] [3,2,1,3]。求有多少个匹配的括号子片段。

分析:
说在前面,这一段都比较抽象,可以自己在纸上模拟一下过程。感觉描述不是很到位,可以边看代码边模拟手算理解
s u m sum sum维护可能对后续有影响的左括号数量
分成奇偶讨论,如果是奇数位置,当前是左括号,直接加上左括号的数量 c c c
如果当前是偶数位置,则是右括号的数量 c c c,用 r e s res res维护最后的结果,当前 r e s res res肯定要加上 m i n ( s u m , c ) min(sum,c) min(sum,c)
然后 s u m sum sum减去右括号的数量 c ( s u m − = c ) c(sum-=c) c(sum=c)这个时候我们需要判断当前的匹配括号在后面的匹配括号中,是否能够形成新的子片段
如果此时 s u m < 0 sum<0 sum<0。说明在当前位置的右括号数量比左侧的左括号数量还多,那么当前包括左侧括号一定在后续的过程中无法构成新的括号子片段了,将 s u m sum sum 0 0 0,当前包括左侧括号全部清空,对后续操作没有影响了。
我们将当前 s u m sum sum存储在 s s s数组中,因为在后面的匹配了的括号中,可能还会形成新的括号子片段。所以当前的 s u m sum sum还需要判断是否能够和之前匹配的括号中,形成新的匹配子片段。我们遍历之前存储的 s s s数组