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

Posted 行码棋

tags:

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

A

题意:
两个数为0,问把两个数进行题目上的操作变为给出的数的最小次数

思路:
找规律
1.优先将两个数变为给出两个数的中间值 ( a + b ) / 2 (a+b)/2 (a+b)/2,然后一加一减就能变成目标值

2.如果两个数之和为奇数则不能操作
3.两个数相等,一次操作即可
4.为0,不需操作

#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef vector<int> vi;
typedef vector<ll> vl;
const int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
const int inf = 0x3f3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-6;
const int mod = 1e9+7;
const int N = 2e5+5,M = 2e5+5;

ll n,m,k;

void solve()
{
	int a,b;
	cin>>a>>b;
	if(a==0 and b==0) cout<<0<<'\\n';
	else if(a==b) cout<<1<<'\\n';
	else if((a+b)%2==0) cout<<2<<'\\n';
	else cout<<-1<<"\\n";
}
int main()
{
//	ios::sync_with_stdio(false);
//	cin.tie(0),cout.tie(0);
	int _;
	cin>>_;
//	_ = 1;
	while(_--)
	{
		solve();
	}
	return 0;
}
 

B

题意:
一个序列,可以对奇偶相邻的两个数进行交换,问将这个序列变为奇偶相间的序列所需要的最小的交换次数

思路:
1.首先排除特殊的情况:奇数和偶数的个数差大于1,一定不可以奇偶相间
2.然后对于奇数进行考虑:
最后的结果一定是奇偶相隔的,那么奇数要么在1,3,5…位置,要么在2,4,6,…位置,从前往后遍历数组,如果是奇数,需要将这个数放在相应的位置,求当前下标与目标位置坐标之差,即为当前奇数移到正确位置的交换次数。
3.然后所有的情况都可以只考虑奇数
奇数个数大于等于偶数个数时,可能是奇偶奇偶(第一位),奇偶奇偶奇(第一位),偶奇偶奇(最后一位),奇数会第一位,也可能是最后一位,那么我们取最小值即可
偶数个数大于奇数个数时,只能是偶奇偶的形式,奇数位于2,4,…位置,求值即可

#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef vector<int> vi;
typedef vector<ll> vl;
const int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
const int inf = 0x3f3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-6;
const int mod = 1e9+7;
const int N = 1e5+5,M = 2e5+5;

ll n,m,k;
int a[N];

void solve()
{
	cin>>n;
	int odd=0,eve=0;
	for(int i=1;i<=n;i++) 
	{
		cin>>a[i];
		if(a[i]&1) odd++;
		else eve++;
	}
	if(abs(odd-eve)>1)
	{
		cout<<-1<<'\\n';
		return;
	} 
	int res = 0;
	int cur = 1;
	if(odd>=eve)
	{
		for(int i=1;i<=n;i++)
		{
			if(a[i]&1)
			{
				res += abs(cur-i);
				cur += 2;
			}	
		}
		int t = 0;
		cur = n;
		for(int i=n;i>=1;i--)
		{
			if(a[i]&1)
			{
				t += abs(cur-i);
				cur -= 2;
			}
		}
		res = min(res,t);
	}
	else
	{
		cur = 2;
		int t = 0;
		for(int i=1;i<=n;i++)
		{
			if(a[i]&1) 
			{
				t += abs(cur-i);
				cur += 2;
			}
		}
		res = t;
	}
	cout<<res<<'\\n';
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int _;
	cin>>_;
//	_ = 1;
	while(_--)
	{
		solve();
	}
	return 0;
}
 

C

题意:一个序列,奇数位表示左括号的个数,偶数位表示右括号的个数,求序列所代表的括号能够匹配成括号对的所有子序列的数目(序列要求必须连续)

思路:
sl表示匹配左边括号需要右括号的最小匹配数量
sr表示匹配左边括号需要右括号的最大匹配数量
(为啥有最小最大匹配长度呢,
5 3 6 3 这个例子,初始 sl = 1,sr = 5,
下面求到第二位时因为sl<a[j](当前右括号数量a[j]能够达到最小需要的数量才能进行计算结果)可以计算对结果的贡献
m i n ( a [ j ] , s r ) − s l + 1 min(a[j],sr)-sl+1 min(a[j],sr)sl+1 m i n ( a [ j ] , s r ) min(a[j],sr) min(a[j],sr)为当前右括号的数量和可以匹配的需要最大右括号数量最小值,即为可以匹配成括号对的数量,但是因为中间可能有左括号的消耗(sl是最小需要右括号的数量),则需要减去sl加1
这时候肯定是能匹配成功的,sl肯定会消除,所以变为0,需要最大的右括号因为匹配过a[j]个,需要减去a[j]
如果当前最小需要有括号的数量大于需要右括号的最大数量,需要退出循环

遍历每个奇数位(左括号),我们求能够当前左括号能够匹配成括号对的个数(相当于求每个左括号对总体的括号对贡献)
第一层循环求每个左括号能组成括号对的贡献
第二层循环求每个左括号组成括号对的总贡献
j为奇数时,加上左括号的数量,那么相应的需要右括号的最小和最大数量都会增加
j为偶数时,进行上述例子中的相关操作就可

#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef vector<int> vi;
typedef vector<ll> vl;
const int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
const int inf = 0x3f3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-6;
const int mod = 1e9+7;
const int N = 1e5+5,M = 2e5+5;

int n,m,k;
ll a[N];

void solve()
{
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	ll res = 0;
	for(int i=1;i<=n;i+=2)
	{
		ll sl = 1,sr = a[i];
		for(int j=i+1;j<=n;j++)
		{
			if(j&1) sl+=a[j],sr+=a[j];
			else
			{
				if(sl>a[j])
				{
					sl -= a[j],sr -= a[j];
					continue;
				}
				res += min(a[j],sr)-sl+1;
				sl = 0,sr -= a[j];
				if(sl > sr) break;
			}
		}
	}
	cout<<res<<'\\n';
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int _;
//	cin>>_;
	_ = 1;
	while(_--)
	{
		solve();
	}
	return 0;
}
 

D

题意:
交互题,可以询问两个位置的数的或运算和与运算的结果,最多询问2n次,求第k小的数是什么

思路:
我们可以得到一个性质: a + b = a ∣ b + a & b a + b = a|b + a \\&b a+b=ab+a&b
那么对于三个数 a 1 , a 2 , a 3 a_1,a_2,a_3 a1,a2,a3,我们询问六次,可以得到三个数两两之和的值,解方程就可以得到各自的值
这题有一个很巧的方法,求第 a 1 a_1 a1和其它值各自的和,共 2 ∗ ( n − 1 ) 2*(n-1) 2(n1)次询问,最后再询问两次求 a 2 + a 3 a_2+a_3 a2+a3的值,利用 a 1 + a 2 , a 1 + a 3 , a 2 + a 3 a_1+a_2,a_1+a_3,a_2+a_3 a1+a2,a1+a3,a2+a3可以求解出 a 1 a_1 a1,然后其他的值就是他们与 a 1 a_1 a1的和减去 a 1 a_1 a1.
最后将数组排序就行

#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef vector<int> vi;
typedef vector<ll> vl;
const int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
const int inf = 0x3f3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-6;
const int mod = 1e9+7;
const int N = 1e5+5,M = 2e5+5;

int n,m,k;
ll a[N];

void solve()
{
	cin>>n>>k;
	for(int i=2;i<=n;i++)
	{
		cout<<"or 1 "<<i<<endl;
		cin>>a[i];
	}
	forDeltix Round, Summer 2021 Div. 1 + Div. 2 A B C D

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

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

Deltix Round, Summer 2021 (open for everyone, rated, Div. 1 + Div. 2) D. Take a Guess (交互,位运算性质)(代码片

Deltix Round, Spring 2021 (open for everyone, rated, Div. 1 + Div. 2)

Deltix Round,Spring2021(open for everyone,rated,Div.1+Div.2)