Codeforces Deltix Round, Summer 2021题解

A. A Variety of Operations

如果两个数相差是奇数,就输出-1。
如果相差是偶数,就输出2
相等就输出0

#include <bits/stdc++.h>
using namespace std;
int main()
{
   int n;
   cin>>n;
	for( int i=1;i<=n;i++){
		int a,b;
		cin>>a>>b;
		if(abs(a-b)%2==1){
			cout<<-1<<endl;
		}
		else if(a==0&&b==0){
			cout<<0<<endl;
		}
		else if(a==b){
			cout<<1<<endl;
		}
		else {
			cout<<2<<endl;
		}
	}
}

Take Your Places!

先判断能不能实现,如果不能实现输出-1。
因为最终情况是奇偶相间,因此最终每个数的位置显而易见。
只需将每个数的初始位置存储起来,再计算与最终位置的距离。

#include <bits/stdc++.h>
using namespace std;
long long  a[100100];
int main()
{
   int t;
   cin>>t;
   while(t--){
	   	int n;
	   	cin>>n;
	   	vector<int>odd;
	   	int cntodd=0,cnteven=0;
	   	for( int i=1;i<=n;i++){
	   		cin>>a[i];
	   		a[i]%=2;
	   		if(a[i]==1){
	   			odd.push_back(i);
				cntodd++;	
			}
			else {
				cnteven++;
			}
		}
		if(abs(cntodd-cnteven)>1){
			cout<<-1<<endl;
			continue;
		}
		long long  res=0,res2=0;
		if(cntodd==cnteven)
		for( int i=0;i<odd.size();i++){
			res+=abs(odd[i]-(i*2+1));
		}
		if(cntodd==cnteven){
			for( int i=0;i<odd.size();i++){
				res2+=abs(odd[i]-((i+1)*2));
			}
		}
		else if(cntodd>cnteven){
			for( int i=0;i<odd.size();i++){
				res+=abs(odd[i]-(i*2+1));
			}
		}
		else{
			for( int i=0;i<odd.size();i++){
				res+=abs(odd[i]-((i+1)*2));
			}
		}
		if(cntodd==cnteven)//这里注意要分两种情况讨论122211 
		cout<<min(res,res2)<<endl;
		else{
			cout<<res<<endl;
		}
		
   }
}

C. Compressed Bracket Sequence

枚举左右区间,左右区间节点分别为i和j
使用left变量代表i节点上的左括号数量,使用other代表区间内除了left之外,未配对的左括号数量,显然,当other大于0时,当前组合的开始点不是i,因此不符合题意。
下面循环右端点j,分为以下两种情况:

  1. 当循环到左括号时,other+=a[ j ]
  2. 当循环到右括号时:分为一下几种情况:
    1. 若a[ j ] < other 那么配对之后other中还存在没有配对的括号,因此ans不变,执行other -= a[j];continue;
    2. 若a[ j ]==other 那么这时other中的括号正好全部配对。如果left中有配对的括号(mark!=0),那么ans++。反之continue
    3. 若a[ j ]>other 那么此时other中的括号全部配对,如果mark==1ans++,而且还溢出一些右括号(此时令mark=1)other变为0。将这些右括号与left配对ans+=min(left,remain)
    并且计算left的剩余值left-=remain如果left为负值,说明右括号有多余,此时直接break。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[1010];
int main(){
	int n;
	cin>>n;
	ll ans=0;
	for( int i=1;i<=n;i++) cin>>a[i];
	for( int i=1;i<=n;i+=2){
		ll left=a[i],mark=0,other=0;
		for( int j=i+1;j<=n;j++){
			if(j%2==1){
				other+=a[j];
				continue;
			}
			if(a[j]<other) {
				other-=a[j];
				continue;
			}
			if(a[j]>=other){
				if(mark!=0) ans++;
				ll temp=a[j]-other;
				if(temp>0) mark=1;
				ans+=min(temp,left);
				left-=temp;
				other=0;
			}
			if(left<0) break;
		}
//		cout<<i<<" "<<ans<<endl;
	}
	cout<<ans<<endl;
}

D. Take a Guess

只需一个公式:a&b+a|b==a+b
利用公式将所有的数都算出来

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll sum[30010];
ll val[30010];
ll val2[30010];
int main(){
	int n,k;
	cin>>n>>k;
	for( int i=1;i<=n;i++){
		int OR=0,AND=0;
		if(i%3!=0){
			cout<<"or"<<" "<<i<<" "<<(i+1)%(n+1)+(bool)(!((i+1)%(n+1)))<<endl;
			fflush(stdout);
			cin>>OR;
			cout<<"and"<<" "<<i<<" "<<(i+1)%(n+1)+(bool)(!((i+1)%(n+1)))<<endl;
			fflush(stdout);
			cin>>AND;
			sum[i]=AND+OR;
		}
		else{
			cout<<"or"<<" "<<i<<" "<<(i-2)%n<<endl;
			fflush(stdout);
			cin>>OR;
			cout<<"and"<<" "<<i<<" "<<(i-2)%n<<endl;
			fflush(stdout);
			cin>>AND;
			sum[i]=AND+OR;
		}
		
	}
	for( int i=1;i+2<=n;i+=3){
		val[i]=(sum[i]+sum[i+2]-sum[i+1])/2;
		val[i+2]=(sum[i+2]-val[i]);
		val[i+1]=(sum[i+1]-val[i+2]);
	}
	for( int i=n;i>=n-n%3+1;i--){
		if(i==n)
		val[i]=sum[i]-val[1];
		else 
		val[i]=sum[i]-val[i+1];
	}
	for( int i=1;i<=n;i++) val2[i]=val[i];
	sort(val+1,val+1+n);
	cout<<"finish "<<val[k]<<endl;
}

E. Equilibrium

前缀和,线段树
详解:
问题研究的是两个数组的差值,首先将两个数组相减,这里用a[ i ] - b[ i ]
首先讨论不成立的情况:
因为每次需要选择 偶数个 数,而且第一个数必须+1,所以如果某一段的前缀和大于0,那么正数就无法消去,题设就不能成立。而且区间的前缀和必须为0,否则题设也不成立。
再讨论成立的情况:
如果问题成立,那么只需输出前缀和最小值的绝对值。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N 200100
struct node {
	int l,r;
	ll maxn;
	ll minn;
}tr[N*4];
ll a[N],b[N];
ll sub[N];
void creat(int rt,int l,int r){
	tr[rt].l=l,tr[rt].r=r;
	if(l==r) {
		tr[rt].maxn=tr[rt].minn=sub[l];
		return ;
	}
	int mid=(l+r)/2;
	creat(rt*2,l,mid);
	creat(rt*2+1,mid+1,r);
	tr[rt].maxn=max(tr[rt*2].maxn,tr[rt*2+1].maxn);
	tr[rt].minn=min(tr[rt*2].minn,tr[rt*2+1].minn);
}
ll qmax( int rt,int L,int R){
	int l=tr[rt].l,r=tr[rt].r;
	if(l>=L&&r<=R) return tr[rt].maxn;
	if(r<L||l>R) return -1e16;
	int mid=(l+r)/2;
	ll x=-1e16,y=-1e16;
	if(L<=mid) x=qmax(rt*2,L,R);
	if(R>mid) y=qmax(rt*2+1,L,R);
	return max(x,y); 	
}
ll qmin( int rt,int L,int R){
	int l=tr[rt].l,r=tr[rt].r;
	if(l>=L&&r<=R) return tr[rt].minn;
	if(r<L||l>R) return 1e16;
	int mid=(l+r)/2;
	ll x=1e16,y=1e16;
	if(L<=mid) x=qmin(rt*2,L,R);
	if(R>mid) y=qmin(rt*2+1,L,R);
	return min(x,y); 	
}
int main(){
	int n,m;
	cin>>n>>m;
	for( int i=1;i<=n;i++) cin>>a[i];
	for( int i=1;i<=n;i++) cin>>b[i];
	for( int i=1;i<=n;i++) sub[i]=a[i]-b[i];
	for( int i=1;i<=n;i++) sub[i]=sub[i]+sub[i-1];
	creat(1,1,n);
	while( m--){
		int l,r;
		cin>>l>>r;
//		cout<<qmax(1,l,r)<<endl;
		if(sub[l-1]!=sub[r]||qmax(1,l,r)-sub[l-1]>0) {//注意这里判断两个条件
			cout<<-1<<endl;
			continue;
		}
		else{
			cout<<abs(qmin(1,l,r)-sub[l-1])<<endl;
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值