Deltix Round, Summer 2021 (open for everyone, rated, Div. 1 + Div. 2) A-D题解

A. A Variety of Operations

题目: https://codeforces.com/contest/1556/problem/A
题型: 数学
题意:
给定两个正整数数 c c c d d d a = 0 a=0 a=0 b = 0 b=0 b=0,每次可以选择任意一个正整数k,使得
1、 a = a + k a = a + k a=a+k b = b + k b = b + k b=b+k
2、 a = a + k a = a + k a=a+k b = b − k b = b - k b=bk
3、 a = a − k a = a - k a=ak b = b + k b = b + k b=b+k
求至少需要几次使得 a = c a = c a=c b = d b = d b=d
输出最少的次数;如果不可能,则输出-1。

思路:
1、当 c = 0 c = 0 c=0 d = 0 d = 0 d=0时,显然答案为0。
2、当 c = d ≠ 0 c = d ≠ 0 c=d=0时,显然答案为1。
3、当 c c c d d d一奇一偶时,显然不可能,所以答案为-1。
4、(1)当 c c c d d d同奇同偶时,取 k = c + d 2 k = \frac{c+d}{2} k=2c+d,进行操作1,那么 a = c + d 2 a=\frac{c+d}{2} a=2c+d b = c + d 2 b=\frac{c+d}{2} b=2c+d
      (2)若 c > d c>d c>d,取 k = c − d 2 k = \frac{c-d}{2} k=2cd,进行操作2,若 c < d c<d c<d,取 k = c − d 2 k = \frac{c-d}{2} k=2cd,进行操作3。
      通过这两步就能使得 a = c a=c a=c b = d b=d b=d。所以答案为2。

AC代码

#include <iostream>
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){//c和d都等于0
			printf("0\n");
			continue;
		}
		if (c == d){//c和d相等
			printf("1\n");
			continue;
		}
		if ((c + d) % 2 == 1){//一奇一偶
			printf("-1\n");
			continue;
		}
		printf("2\n");//同奇同偶
	}
	return 0;
}

B. Take Your Places!

题目: https://codeforces.com/contest/1556/problem/B
题型: 模拟
题意:
给定一个序列,每次可以交换相邻的两个数,求最少需要多少次,使得序列变成成奇偶相间的序列。
输出最少次数;如果不可以,则输出-1。

思路:
设位置下标为0 ~ n-1。
用cnt1表示奇数的个数,用cnt2表示偶数的个数。
1、当 ∣ c n t 1 − c n t 2 ∣ > 1 \lvert cnt1 - cnt2 \rvert > 1 cnt1cnt2>1时,显然不可能做到奇偶相间,所以输出-1。

2、当 c n t 1 − c n t 2 = 1 cnt1 - cnt2 = 1 cnt1cnt2=1时,排列方法为奇 偶 奇 偶 ...... 奇。所以只需要遍历一遍 c n t 1 cnt1 cnt1,计算第i个奇数的位置与 ( 2 i ) (2i) (2i)的绝对值之差,最终最少次数就是这些差的和。

3、当 c n t 1 − c n t 2 = 1 cnt1 - cnt2 = 1 cnt1cnt2=1时,排列方法为偶 奇 偶 奇 ...... 偶。所以只需要遍历一遍 c n t 1 cnt1 cnt1,计算第i个奇数的位置与 ( 2 i − 1 ) (2i-1) (2i1)的绝对值之差,最终最少次数就是这些差的和。

4、当 c n t 1 = c n t 2 cnt1 = cnt2 cnt1=cnt2时,排列方法为奇 偶 奇 偶 ...... 奇偶 奇 偶 奇 ...... 偶。将两种情况都根据上面的2和3跑一边,更小的那个就是答案。

AC代码

#include <iostream>
#include <cmath>
#include <vector>
using namespace std;

const int N = 1e5+7;
int a[N];
vector<int> v;//用于存储所有奇数的位置

int main(){
	int t;
	scanf("%d", &t);
	while (t--){
		v.clear();//清空
		int n;
		scanf("%d", &n);
		int cnt1 = 0, cnt2 = 0;//分别表示奇数和偶数的个数
		for (int i = 0; i < n; i++){
			int x;
			scanf("%d", &x);
			if (x % 2 == 1){//该数为奇数
				cnt1++;
				v.push_back(i);//将位置放入v中
			}else{
				cnt2++;
			}
		}
		if (abs(cnt1-cnt2) > 1){//当奇数和偶数的个数相差大于1
			printf("-1\n");
			continue;
		}
		int len = v.size();
		if (cnt1 == cnt2){
			int ans1 = 0, ans2 = 0;
			for (int i = 0; i < len; i++){
				ans1 += abs(v[i] - (2*i));//计算“奇 偶 奇 偶 ... 奇”所需的次数
				ans2 += abs(v[i] - (2*i+1));//计算“偶 奇 偶 奇 ... 偶”所需的次数
			}
			int ans = min(ans1, ans2);//更小的那个为答案
			printf("%d\n", ans);
		}else if (cnt1 > cnt2){//奇数比偶数多, “奇 偶 奇 偶 ... 奇”
			int ans = 0;
			for (int i = 0; i < len; i++){
				ans += abs(v[i] - (2*i));
			}
			printf("%d\n", ans);
		}else{//偶数比奇数多, “偶 奇 偶 奇 ... 偶”
			int ans = 0;
			for (int i = 0; i < len; i++){
				ans += abs(v[i] - (2*i+1));
			}
			printf("%d\n", ans);
		}
	}
	return 0;
} 

C. Compressed Bracket Sequence

题目: https://codeforces.com/contest/1556/problem/C
题型: 暴力、模拟
题意:
给定一个长度为n的序列,序列的奇数位表示左括号数量,偶数为表右括号数量,求最多有多少个合法的括号子序列。

思路:
先统计出两两配对的答案数,再对剩余的左括号暴力向后找能配对的右括号,还要统计一下以当前括号为起点可以向后连接多少个括号。

AC代码

#include <iostream>
using namespace std;

typedef long long ll;
const int N = 1e4+7;
ll c[N];

int main(){
	int n;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++){
		scanf("%lld", &c[i]);
	}
	ll ans = 0;
	for (int i = 1; i <= n; i += 2){
		ll x = 0, y = 0;
		if (i < n){
			ans--;
		}
		for (int j = i+1; j <= n; j += 2){
			ans += max(0ll, min(c[i]+y+1, c[j]-x+y+1));
			x -= c[j];
			y = min(x, y);
			x += c[j+1];
		}
	}
	printf("%lld\n", ans);
}

D. Take a Guess

题目: https://codeforces.com/contest/1556/problem/D
题型: 交互、位运算、数学
题意:
交互题,知道一个数组的长度为n、但不知道数组的每一个的值,可以询问不超过2*n次询问,每次询问为:
1、询问and i j,返回a[i] & a[j]
2、询问or i j,返回a[i] | a[j]
求第k大的数字是多少。

思路:
由位运算的知识可知,x&y + x|y = x+y。所以每2次询问同样的i和j便可知道a[i]+a[j]的值。
因此,可以询问and 1 2or 1 2得出sum12,即a[1]+a[2];询问and 2 3or 2 3得出sum23,即a[2]+a[3];询问and 3 1or 3 1得出sum31,即a[3]+a[1]。三元一次方程组求解可得 a [ 1 ] = s u m 12 − s u m 23 + s u m 31 2 a[1] = \frac{sum12-sum23+sum31}{2} a[1]=2sum12sum23+sum31 a [ 2 ] = s u m 23 − s u m 31 + s u m 12 2 a[2] = \frac{sum23-sum31+sum12}{2} a[2]=2sum23sum31+sum12 a [ 3 ] = s u m 31 − s u m 12 + s u m 23 2 a[3] = \frac{sum31-sum12+sum23}{2} a[3]=2sum31sum12+sum23
再接下来2(n-3)次询问,每次询问and 1 ior 1 i得出a[1]+a[i],便可算出a[i]的值。
最后对数组a进行升序排序,a[k]便是所求值。
注意:每次输入询问后要刷新缓冲区,即fflush(stdout)

AC代码

#include <iostream>
#include <algorithm>
using namespace std;

typedef long long ll;
const int N = 10007;
ll a[N];

ll ask(int x, int y){
	ll u, v;
	printf("and %d %d\n", x, y);
	fflush(stdout);//刷新缓冲区
	scanf("%lld", &u);
	printf("or %d %d\n", x, y);
	fflush(stdout);//刷新缓冲区
	scanf("%lld", &v);
	ll ans = u + v;//a+b = a&b + a|b
	return ans;//返回a[x]+a[y]
}

int main(){
	int n, k;
	scanf("%d%d", &n, &k);
	int sum12 = ask(1, 2);//a[1]+a[2]
	int sum23 = ask(2, 3);//a[2]+a[3]
	int sum31 = ask(3, 1);//a[3]+a[1]
	a[1] = (sum12-sum23+sum31)/2;
	a[2] = (sum23-sum31+sum12)/2;
	a[3] = (sum31-sum12+sum23)/2;
	for (int i = 4; i <= n; i++){
		a[i] = ask(1, i) - a[1];
	}
	sort(a+1, a+1+n);
	printf("finish %lld\n", a[k]);
	return 0;
}

*E. Equilibrium

题目: https://codeforces.com/contest/1556/problem/E
待补。。。

*F. Sports Betting

题目: https://codeforces.com/contest/1556/problem/F
待补。。。

*G. Gates to Another World

题目: https://codeforces.com/contest/1556/problem/G
待补。。。

*H. DIY Tree

题目: https://codeforces.com/contest/1556/problem/H
待补。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Chosen_One_13

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值