Codeforces Round 1059 (Div. 3) A-F题解

Codeforces Round 1059 (Div. 3)

https://codeforces.com/contest/2162

第一次div3赛时5题,虽然最后还剩下40多分钟,但是F一直差一点。事实证明我确实赛时写不出来F,比赛结束后F也订了好久。

A. Beautiful Average

显然,找数列最大数输出即可。

#include <bits/stdc++.h>
#define intt long long
#define N
#define debug(x) cout<<#x<<":"<<x<<" ";

using namespace std;
//using namespace __gnu_pbds;
int T,n,m;
void solve()
{
	scanf("%d",&n);
	int maxn=0;
	for(int t=1,u1;t<=n;++t)
	{
		scanf("%d",&u1);
		maxn=max(maxn,u1);
	}
	printf("%d\n",maxn);
}
int main()
{
	cin>>T;
	while(T--)
	{
		solve();
	}
	return 0;
}

B. Beautiful String

注意到选择的是子序列,那么我们可以直接把数列的1给删除,剩下的所有0构成的数列,或者空数列一定满足题意。

#include <bits/stdc++.h>
#define intt long long
#define N
#define debug(x) cout<<#x<<":"<<x<<" ";

using namespace std;
//using namespace __gnu_pbds;
int T,n,m;
void solve()
{
	scanf("%d",&n);
	string s;
	cin>>s;
	vector<int> v;
	for(int t=0;t<s.size();++t)
	{
		if(s[t]=='1')
		{
			v.push_back(t+1);
		}
	}
	printf("%d\n",v.size());
	for(auto i:v)
	{
		printf("%d ",i);
	}
	cout<<endl;
}

int main()
{
	cin>>T;
	while(T--)
	{
		solve();
	}
	return 0;
}

C. Beautiful XOR

出现异或运算,回想一下异或的性质后,可以发现
x 1 ⊕ x 2 ⊕ . . . ⊕ x i = a ⊕ b x_1\oplus x_2 \oplus ...\oplus x_i=a \oplus b x1x2...xi=ab
那么我们每次不妨直接用2的次幂进行异或,可以发现因为a<=1e9,所以运算次数绝对不会超过64次。但是还有个条件是每次的x要小于a,特判即可(这也是为什么每次用2的次幂,这样子可以使每次运算的x尽量小)

#include <bits/stdc++.h>
#define intt long long
#define N
#define debug(x) cout<<#x<<":"<<x<<" "<<endl;

using namespace std;
//using namespace __gnu_pbds;
int T,n,m;
void solve()
{
	int a,b,c,d,e=1;
	vector<int> v;
	cin>>a>>b;
	c=a^b;
	d=c;
	while(d)
	{
		if(d&1)
		{
			if(e>a)
			{
				cout<<-1<<endl;
				return ;
			}
			v.push_back(e);
//			debug(e)
		}
		e<<=1;
		d>>=1;
	}
	if(!v.size())
	{
		cout<<0<<endl;
		return ;
	}
	else
	{
		cout<<v.size()<<endl;
		for(auto i:v)
			cout<<i<<" ";
		cout<<endl;
	}
	return ;
}

int main()
{
	cin>>T;
	while(T--)
	{
		solve();
	}
	return 0;
}

D. Beautiful Permutation

看到这一题,很显然考虑二分,当二分左右区间都有增量时,显然我们就可以确定答案。
需要注意的是,因为有限制询问次数,我们可以用大区间减去左区间从而得到右区间的询问结果,这样子可以减少询问次数。

#include <bits/stdc++.h>
#define intt long long
#define N
#define debug(x) cout<<#x<<":"<<x<<" ";

using namespace std;
//using namespace __gnu_pbds;
int T,n,m;
int yask(int u1,int l,int r)
{
	int u2;
	printf("%d %d %d",u1,l,r);
	cout<<endl;
	scanf("%d",&u2);
	return u2;
}
void yans(int l,int r)
{
	printf("! %d %d",l,r);
	cout<<endl;
	return ;
}
void solve()
{
	scanf("%d",&n);
	int sum1=yask(1,1,n),sum2=yask(2,1,n),len;
	len=sum2-sum1;
	int l=1,r=n;
	while(l<r)
	{
		int mid=(l+r)>>1;
		int now1=yask(1,l,mid),now2=yask(2,l,mid);
		int now3=sum1-now1,now4=sum2-now2;
		if(now2-now1>0&&now4-now3>0)
		{
			yans(mid-(now2-now1)+1,mid+(now4-now3));
			return ;
		}
		if(now2-now1)
		{
			r=mid;
			sum1=now1;
			sum2=now2;
		}
		else 
		{
			l=mid+1;
			sum1=now3;
			sum2=now4;
		}
	}
	yans(l,r);
	return ;
}
int main()
{
	cin>>T;
	while(T--)
	{
		solve();
	}
	return 0;
}

E. Beautiful Palindromes

此题我和大众思路并不一样。
我的思路是分成两种情况进行讨论:

第一种是全部数字都不同,这样子显然我们只需要复制粘贴一遍序列是最优的。

第二种情况是有数字是相同,这种情况下,绝对会有数字在原序列未出现,我们优先把这些数字添加,然后我们之后添加数字时,因为我们至少添加过一个原序列未出现的数字,如果回文序列不以它为中心的话,一定不存在;如果回文序列以它为中心,我们就尽量不选和原序列对应位置相同的数字即可。

#include <bits/stdc++.h>
#define intt long long
#define N 200005
#define debug(x) cout<<#x<<":"<<x<<" ";

using namespace std;
//using namespace __gnu_pbds;
int T,n,m,k;
int a[500005];
bool valid[N];
void solve()
{
	scanf("%d%d",&n,&k);
	for(int t=1;t<=n;++t) valid[t]=0;
	vector<int> v1,v2;
	deque<int> q;
	for(int t=1;t<=n;++t)
	{
		scanf("%d",&a[t]);
		if(!valid[a[t]])
		{
			valid[a[t]]=1;
			v1.push_back(a[t]);
			q.push_back(a[t]);
		}
	}
	for(int t=1;t<=n;++t)
	{
		if(!valid[t])
		{
			v2.push_back(t);
		}
	}
	if(!v2.size())
	{
		for(int t=1;t<=n&&t<=k;++t)
		{
			printf("%d ",a[t]);
		}
		cout<<endl;
		return ;
	}
	for(int t=0;t<v2.size()&&t<k;++t)
	{
		printf("%d ",v2[t]);
	}
	for(int t=n+v2.size()+1;t<=n+k;++t)
	{
		if(q.front()==a[n*2+2-t])
		{
			printf("%d ",q.back());
			q.pop_back();
		}
		else
		{
			printf("%d ",q.front());
			q.pop_front();
		}
	}
	cout<<endl;
	return ;
}
int main()
{
	cin>>T;
	while(T--)
	{
		solve();
	}
	return 0;
}

F. Beautiful Intervals

一个重要的结论是, m e x ( M ) = 0 , 1 , 2 mex(M)=0,1,2 mex(M)=0,1,2,不可能再有其他值,因为我们一定可以构造出
( . . . , 0 , 2 , 1 , . . . ) (...,0,2,1,...) (...,0,2,1,...)这样的数列使得 m e x < = 2 mex<=2 mex<=2
对于使 m e x = 0 和 m e x = 1 mex=0和mex=1 mex=0mex=1的情况,前者是所有区间都有一个位置重合,那个重合的位置是0的位置;后者是要存在一个位置不是一个区间的起点和一个区间的终点,这个位置是0的位置,然后把1放到和0相邻的位置即可。
对于后者,这个很容易写错,我是参考cf官方的题解写的,不知道有没有更好的写法。

#include <bits/stdc++.h>
#define intt long long
#define N 3010
#define debug(x) cout<<#x<<":"<<x<<" ";

using namespace std;
//using namespace __gnu_pbds;
int T,n,m,sum[N],spj1[N],spj2[N];
void solve()
{
	scanf("%d%d",&n,&m);
	for(int t=1;t<=n;++t) sum[t]=0,spj1[t]=0,spj2[t]=0;
	for(int t=1,u1,u2;t<=m;++t)
	{
		scanf("%d%d",&u1,&u2);
		sum[u1]++;
		sum[u2+1]--;
		spj1[u1]=1;
		spj2[u2]=1;
	}
	for(int t=1,now=0;t<=n;++t)
	{
		now+=sum[t];
		if(now==m)
		{
			for(int i=1,u1=1;i<=n;++i)
			{
				if(i!=t)
				{
					printf("%d ",u1);
					++u1;
				}
				else
				{
					printf("0 ");
				}
			}
			return ;
		}
	}
	for(int t=1;t<n;++t)
	{
		int u1,u2;
		if(!spj2[t])
		{
			u1=t;
			u2=t+1;
			for(int i=1,u3=2;i<=n;++i)
			{
				if(i==u1) printf("0 ");
				else if(i==u2) printf("1 ");
				else
				{
					printf("%d ",u3);
					++u3;
				}
			}
			return ;
		}
		if(!spj1[t+1])
		{
			u1=t+1;
			u2=t;
			for(int i=1,u3=2;i<=n;++i)
			{
				if(i==u1) printf("0 ");
				else if(i==u2) printf("1 ");
				else
				{
					printf("%d ",u3);
					++u3;
				}
			}
			return ;
		}
	}
	
	for(int t=1;t<=n;++t)
	{
		if(t==1) printf("0 ");
		else if(t==2) printf("2 ");
		else if(t==3) printf("1 ");
		else printf("%d ",t-1);
	}
	return ;
}
int main()
{
	cin>>T;
	while(T--)
	{
		solve();
		cout<<endl;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值