Codeforces Round #843 (Div. 2) A ~ C 题解

A1&A2 Gardener and the Capybaras

题意

简单版本: A1
困难版本: A2
一个字符串,只包含a和b两种字母,请将这个字符串划分为三个非空字符串,使得第二个字符串的字典序最大或最小。困难版本的数据范围要求此题在线性时间复杂度下解决。

思路

就是用分类讨论的思想去构造,具体的构造方法见代码。这种构造题的构造方法很多,顺水推舟就能做出来。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 5e5 + 5;
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	ll t;
	cin>>t;
	while(t--){
		string s;
		cin>>s;
		ll n=s.length()-1;
		if(s[0]=='a'&&s[n]=='a'){
			cout<<"a"<<" ";
			for(ll i=1;i<n;i++)cout<<s[i];
			cout<<" ";
			cout<<"a"<<endl;
		}
		else if(s[0]=='b'&&s[n]=='b'){
			cout<<"b"<<" ";
			for(ll i=1;i<n;i++)cout<<s[i];
			cout<<" ";
			cout<<"b"<<endl;
		}
		else if(s[0]=='a'&&s[n]=='b'){
			cout<<"a"<<" ";
			if(s[1]=='a'){
				cout<<"a"<<" ";
				for(ll i=2;i<=n;i++)cout<<s[i];
				cout<<endl;
			}
			else{
				for(ll i=1;i<n;i++)cout<<s[i];
				cout<<" ";
				cout<<"b"<<endl;
			}
		}
		else{
			cout<<"b"<<" ";
			if(s[1]=='a'){
				cout<<"a"<<" ";
				for(ll i=2;i<=n;i++)cout<<s[i];
				cout<<endl;
			}
			else{
				for(ll i=1;i<n;i++)cout<<s[i];
				cout<<" ";
				cout<<"a"<<endl;
			}
		}
	}
    return 0;
}

B. Gardener and the Array

题意

题目链接
就是给你一个数组,这个数组中的数都是大数,用二进制位表示。问能不能选出两个不同的子数组,使得这两个子数组各自所有的数按位或的值相同。

思路

由于是大数,而且数据范围不够明确,这个题需要开动态数组和键值对存储。说白了,对于某一个大数的每一位,都满足:如果这一位是1,而且其他大数中至少有一个在这一位上也是1,那就符合题意。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 1e5 + 5;
vector<ll> v[maxn];
map<ll,ll> cnt;
int main(){
	//ios::sync_with_stdio(0);
	//cin.tie(0),cout.tie(0);
	ll t;
	scanf("%lld",&t);
	while(t--){
		ll n;
		scanf("%lld",&n);
		for(ll i=1;i<=n;i++)v[i].clear();
		cnt.clear();
		ll bit = -1e9;
		for(ll i=1;i<=n;i++){
			ll k;scanf("%lld",&k);
			for(ll j=0;j<k;j++){
				ll x;scanf("%lld",&x);
				bit=max(bit,x);
				v[i].push_back(x);
			}
		}
		for(ll i=1;i<=n;i++){
			for(auto j: v[i]){
				cnt[j]++;
			}
		}
		bool flag=false;
		for(ll i=1;i<=n;i++){
			bool f=true;
			for(auto j: v[i]){
				if(cnt[j]==1){
					f=false;break;
				}
			}
			if(f==true){
				flag=true;
				break;
			}
		}
		if(flag==true)printf("Yes\n");
		else printf("No\n");
	}
    return 0;
}

C. Interesting Sequence

题意

题目链接
求出最小的 m ≥ n m≥n mn,使得 n & ( n + 1 ) & … … & m = x n\&(n+1)\&……\&m=x n&(n+1)&……&m=x

思路

分四种情况讨论,分别看对于某一位 i i i的具体情况:
n i = 0 , x i = 0 n_{i}=0,x_{i}=0 ni=0,xi=0,对答案不构成影响。
n i = 1 , x i = 0 n_{i}=1,x_{i}=0 ni=1,xi=0,说明在 [ n , m ] [n,m] [n,m]范围内,至少存在一个数的第 i i i位是 0 0 0
n i = 0 , x i = 1 n_{i}=0,x_{i}=1 ni=0,xi=1,无解,输出 − 1 -1 1
n i = 1 , x i = 1 n_{i}=1,x_{i}=1 ni=1,xi=1,说明在 [ n , m ] [n,m] [n,m]范围内,所有数的第 i i i位都是 1 1 1

对于④,一旦存在有更高位的②,那么就不合法。因为在逐个 & \& &的过程中必然会遇上 0 0 0的情况。即高位有进位,那么低位也必然都变成 0 0 0

所有②的最高位是影响最大的,我们需要找到这个位。然后判断是否在比这个位小的位上存在④。如果存在,输出 − 1 -1 1

假设最高位的②是 p o s pos pos,那么最终答案就是:
原来 n n n上位置比 p o s pos pos大的 p o s + 1 pos+1 pos+1这一位置 1 1 1,这一位前面都是 0 0 0,后面就是原来 n n n的二进制位数值。如果原来 n n n上的 p o s + 1 pos+1 pos+1这一位就是 1 1 1,那么 p o s pos pos位是 0 0 0 p o s + 1 pos+1 pos+1位必然产生进位,那么这一位原来的 1 1 1必然成为 0 0 0,就不满足④,因此输出 − 1 -1 1

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 64 + 5;
ll bitn[maxn],bitx[maxn],m[maxn];
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	ll t;
	cin>>t;
	while(t--){
		ll n,x;
		cin>>n>>x;
		memset(bitn,0,sizeof(bitn));
		memset(bitx,0,sizeof(bitx));
		ll cntn=0,cntx=0;
		ll nn=n,xx=x;
		while(nn){
			bitn[cntn++]=(nn&1);
			nn=nn>>1;
		}
		while(xx){
			bitx[cntx++]=(xx&1);
			xx=xx>>1;
		}
		bool flag=true;
		for(ll i=0;i<max(cntn,cntx);i++){
			if(bitn[i]==0&&bitx[i]==1){
				flag=false;
				break;
			}
		}
		ll pos=-1;
		for(ll i=0;i<max(cntn,cntx);i++){
			if(bitn[i]==1&&bitx[i]==0)pos=i;
		}
		for(ll i=0;i<max(cntn,cntx);i++){
			if(bitn[i]==1&&bitx[i]==1){
				if(pos>i){
					flag=false;
					break;
				}
			}
		}
		if(flag==false)cout<<-1<<endl;
		else{
			if(pos==-1)cout<<n<<endl;
			else if(bitn[pos+1]==1&&bitx[pos+1]==1)cout<<-1<<endl;
            else{
            	for(ll i=0;i<=pos;i++)m[i]=0;
				m[pos+1]=1;
				if(pos+1==cntn)cntn++;
				for(ll i=pos+2;i<cntn;i++)m[i]=bitn[i];
				ll ans = 0;
				for(ll i=0;i<cntn;i++)ans+=(1LL<<i)*m[i];
				cout<<ans<<endl;
			}
		}
	}
    return 0;
}

心得

这场比赛的题风格很相似,基本就是二进制位或者两个字符的操作,非常考验分类讨论和梳理脉络的思想。每个题细节都很多,比赛时需要在草稿纸上对每种情况逐个理清,多分析几个样例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

keguaiguai

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

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

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

打赏作者

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

抵扣说明:

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

余额充值