Codeforces Global Round 12 A-D题解

A

题意
给你一个字符串 a a a,重新排列其中的元素,使 a a a中不包含"trygub"这个子序列。

分析
a a a中包含的子序列中的 6 6 6个字符倒排即可。

代码

#include<bits/stdc++.h>
#define ll long long
#define FULL(x,y) memset(x,y,sizeof(x))
#define pb push_back
using namespace std;
 
string str="bugyrt";
int t,n;
string s;
 
int main() {
	cin>>t;
	while(t--) {
		cin>>n>>s;
		int c[26]={0};
		for(int i=0;i<n;i++) {
			c[s[i]-'a']++;
		}
		string res="";
		for(int i=0;i<6;i++) {
			for(int j=0;j<c[str[i]-'a'];j++) res+=str[i];
		}
		for(int i=0;i<26;i++) {
			if (i!='b'-'a' && i!='u'-'a' && i!='g'-'a' && i!='y'-'a' && i!='r'-'a' && i!='t'-'a') {
				for(int j=0;j<c[i];j++) res+=i+'a';
			}
		}
		cout<<res<<endl;
	}
	return 0;
}

B

题意
平面上有 n n n个不同的点 ( x 1 , y 1 ) , … , ( x n , y n ) \left( {{x_1},{y_1}} \right), \ldots ,\left( {{x_n},{y_n}} \right) (x1,y1),,(xn,yn),给定一个非负整数 k k k,每次操作可以选择一个点 i i i,与这个点的曼哈顿距离小于等于 k k k的点会被其吸引,移动到 i i i的位置,问最少要多少次操作能使所有点移动到同一位置,或者说明这是不可能的。

分析
对任意点 i i i来说,对其进行一次操作,若不能把所有点都吸引,则再怎么操作也无法使所有点到达同一位置,因此要么不可能,要么只操作 1 1 1次就行,所以我们每个点都试一次。

代码

#include<bits/stdc++.h>
#define ll long long
#define FULL(x,y) memset(x,y,sizeof(x))
#define pb push_back
using namespace std;
 
const int N=105;
int t,n,k;
int x[N],y[N];
 
int main() {
	cin>>t;
	while(t--) {
		cin>>n>>k;
		int fl=0;
		for(int i=1;i<=n;i++) cin>>x[i]>>y[i];
		for(int i=1;i<=n;i++) {
			int cnt=0;
			for(int j=1;j<=n;j++) {
				if (i==j) continue;
				if (abs(x[i]-x[j])+abs(y[i]-y[j])<=k) {
					cnt++;
				}
			}
			if (cnt==n-1) {
				fl=1;
				break;
			}
		}
		if (!fl) cout<<-1<<endl;
		else cout<<1<<endl;
	}
	return 0;
}

C1(Easy Version)

题意
给你一个 n × n n\times n n×n的矩阵,其中包含一种为’X’的符号,若三个连续相同的符号出现在某行或某列,矩阵是不合格的。每次操作可以选择一个’X’,将其变为’O’,或者选择一个’O’,将其变为’X’,问是否能在不超过 ⌊ k 3 ⌋ \left\lfloor {\frac{k}{3}} \right\rfloor 3k的操作次数下,将矩阵变为合格的矩阵,其中 k k k为矩阵中’X’和’O’的总数。

分析
C1和C2都是非常精彩的构造题。我们可以考虑将矩阵用 3 3 3种颜色染色,对于 ( i , j ) \left( {i,j} \right) (i,j)位置来说(索引从 0 0 0开始),将其染成 ( i + j ) % 3 (i + j)\% 3 (i+j)%3这种颜色,将矩阵分为三部分,此时我们只需将三种颜色对应位置中数量少的那部分的’X’变为’O’即可满足要求。假设三种颜色里’X’的数量分别为 a 0 {a_0} a0 a 1 {a_1} a1 a 2 {a_2} a2,有 min ⁡ { a 0 , a 1 , a 2 } ≤ ⌊ k 3 ⌋ , k = a 0 + a 1 + a 2 \min \left\{ {{a_0},{a_1},{a_2}} \right\} \le \left\lfloor {\frac{k}{3}} \right\rfloor ,k = {a_0} + {a_1} + {a_2} min{a0,a1,a2}3k,k=a0+a1+a2

代码

#include<bits/stdc++.h>
#define FULL(x,y) memset(x,y,sizeof(x))
#define ll long long
#define pb push_back
using namespace std;
 
const int N=305;
int t,n;
char c[N][N];
int a[3];
 
int main() {
	cin>>t;
	while(t--) {
		cin>>n;
		FULL(a,0);
		for(int i=0;i<n;i++) {
			for(int j=0;j<n;j++) {
				cin>>c[i][j];
			}
		}
		for(int i=0;i<n;i++) {
			for(int j=0;j<n;j++) {
				if (c[i][j]=='X') {
					a[(i+j)%3]++;
				}
			}
		}
		int ans=100000,id=0;
		for(int i=0;i<3;i++) {
			if (a[i]<ans) {
				ans=a[i];
				id=i;
			}
		}
		for(int i=0;i<n;i++) {
			for(int j=0;j<n;j++) {
				if ((i+j)%3==id && c[i][j]=='X') cout<<'O';
				else cout<<c[i][j];
			}
			cout<<endl;
		}
	}
	return 0;
}

C2(Hard Version)

题意
C1中初始只包含’X’符号,C2中初始既包含’X’,又包含’O",其他条件不变。

分析
在C1中,将’X’变为’O’,‘O’是不会出现行列上三个连续的情况的,但在C2中,在将’X’变为’O’或者’O’变为’X’时,可能改变后的’X’或’O’又会形成三个连续的情况。其实这里可以分开来看,先选择一种颜色,将其中的’X’变为’O’,很自然的想法是希望改变的位置不再去变动,因此再选另一种颜色,将其中的’O’变为’X’,这样也不会对之前的’X’造成影响,因为变’X’和变’O’是在不同的颜色下进行的。因此,假设初始三种颜色中’X’和’O’的数量分别为 { a 0 , a 1 , a 2 } \left\{ {{a_0},{a_1},{a_2}} \right\} {a0,a1,a2} { b 0 , b 1 , b 2 } \left\{ {{b_0},{b_1},{b_2}} \right\} {b0,b1,b2},我们选择 min ⁡ i ≠ j { a i + b j } \mathop {\min }\limits_{i \ne j} \{ {a_i} + {b_j}\} i=jmin{ai+bj}对应的 i i i j j j颜色,改变其中的’X’和’O’即可。此时 min ⁡ i ≠ j { a i + b j } ≤ ⌊ k 3 ⌋ \mathop {\min }\limits_{i \ne j} \{ {a_i} + {b_j}\} \le \left\lfloor {\frac{k}{3}} \right\rfloor i=jmin{ai+bj}3k也是成立的。

代码

#include<bits/stdc++.h>
#define FULL(x,y) memset(x,y,sizeof(x))
#define ll long long
#define pb push_back
using namespace std;
 
const int N=305;
int t,n;
char c[N][N];
int a[3],b[3];
 
int main() {
	cin>>t;
	while(t--) {
		cin>>n;
		FULL(a,0),FULL(b,0);
		for(int i=0;i<n;i++) {
			for(int j=0;j<n;j++) {
				cin>>c[i][j];
			}
		}
		for(int i=0;i<n;i++) {
			for(int j=0;j<n;j++) {
				if (c[i][j]=='X') {
					a[(i+j)%3]++;
				}
				if (c[i][j]=='O') {
					b[(i+j)%3]++;
				}
			}
		}
		int ans=100000,ida=0,idb=0;
		for(int i=0;i<3;i++) {
			for(int j=0;j<3;j++) {
				if (i==j) continue;
				if (a[i]+b[j]<ans) {
					ans=a[i]+b[j];
					ida=i,idb=j;
				}
			}
		}
		for(int i=0;i<n;i++) {
			for(int j=0;j<n;j++) {
				if ((i+j)%3==ida && c[i][j]=='X') cout<<'O';
				else if ((i+j)%3==idb && c[i][j]=='O') cout<<'X';
				else cout<<c[i][j];
			}
			cout<<endl;
		}
	}
	return 0;
}

D

题意
给定一个数组 a a a,定义数组 a a a k k k倍压缩数组 b b b中的元素为 a a a的每个连续 k k k长子数组的最小值,即 b j = min ⁡ j ≤ i ≤ j + k − 1 a i {b_j} = \mathop {\min }\limits_{j \le i \le j + k - 1} {a_i} bj=jij+k1minai b b b的长度为 n − k + 1 n-k+1 nk+1。对于 1 ≤ k ≤ n 1 \le k \le n 1kn,判断每个数组 b b b是否是 { 1 , 2 , … , n − k + 1 } \{ 1,2, \ldots ,n - k + 1\} {1,2,,nk+1}的一个排列。
数据范围: 1 ≤ n ≤ 3 ⋅ 1 0 5 1 \le n \le 3 \cdot {10^5} 1n3105

分析
k = 1 k=1 k=1时,判断数组是否是 { 1 , 2 , … , n } \{ 1,2, \ldots ,n\} {1,2,,n}的一个排列; k = n k=n k=n时,判断数组的最小值是否为 1 1 1 1 < k < n 1 < k < n 1<k<n时,要满足 { 1 , 2 , … , n − k + 1 } \{ 1,2, \ldots ,n - k + 1\} {1,2,,nk+1}的一个排列,最小值 1 1 1只能出现 1 1 1次,且位置只能在 1 1 1或者 n n n,假设 a [ 1 ] = 1 a[1] = 1 a[1]=1,那么在 [ 2 , n ] [2,n] [2,n]的区间需要满足 a [ 2 ] = 2 a[2]=2 a[2]=2或者 a [ n ] = 2 a[n]=2 a[n]=2,且 2 2 2为最小值,以此类推。因此每次对区间 [ l , r ] [l,r] [l,r],需要满足1. ( a [ l ] = i ∣ ∣ a [ r ] = i ) & & ( min ⁡ l ≤ j ≤ r a [ j ] = i ) , 1 < i < n \left( {a[l] = i||a[r] = i} \right)\& \& \left( {\mathop {\min }\limits_{l \le j \le r} a[j] = i} \right),1 < i < n (a[l]=ia[r]=i)&&(ljrmina[j]=i),1<i<n,此时对于 k = n − i + 1 k=n-i+1 k=ni+1 b b b数组满足要求。注意对于只满足 min ⁡ l ≤ j ≤ r a [ j ] = i {\mathop {\min }\limits_{l \le j \le r} a[j] = i} ljrmina[j]=i的情况也是成立的,但之前的 i i i都必须满足1.条件。这里判断区间最小值可以通过一个计数数组实现。

代码

#include<bits/stdc++.h>
#define ll long long
#define FULL(x,y) memset(x,y,sizeof(x))
#define pb push_back
using namespace std;
 
const int N=300005;
int t,n;
int a[N],res[N],f[N];
 
int main() {
	cin>>t;
	while(t--) {
		cin>>n;
		int minnum=N,fl=0;
		FULL(f,0),FULL(res,0);
		for(int i=1;i<=n;i++) {
			cin>>a[i];
			minnum=min(minnum,a[i]);
			f[a[i]]++;
			if (f[a[i]]>1) {
				fl=1;
			}
		}
		if (minnum==1) res[n]=1;
		if (!fl) res[1]=1;
		int l=1,r=n,cnt=1;
		while(l<r) {
			if (f[cnt]) {
				if (a[l]==cnt) {
					l++,f[cnt]--;
					if (cnt>1 && cnt<n) res[n-cnt+1]=1;
				}
				else if (a[r]==cnt) {
					r--,f[cnt]--;
					if (cnt>1 && cnt<n) res[n-cnt+1]=1;
				}
				else {
					if (r-l+1==n-cnt+1 && cnt>1 && cnt<n) res[n-cnt+1]=1;
					break;
				}
			}
			else break;
			if (f[cnt]) break;
			cnt++;
		}
		for(int i=1;i<=n;i++) cout<<res[i];
		cout<<endl;
	}
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值