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=j≤i≤j+k−1minai,
b
b
b的长度为
n
−
k
+
1
n-k+1
n−k+1。对于
1
≤
k
≤
n
1 \le k \le n
1≤k≤n,判断每个数组
b
b
b是否是
{
1
,
2
,
…
,
n
−
k
+
1
}
\{ 1,2, \ldots ,n - k + 1\}
{1,2,…,n−k+1}的一个排列。
数据范围:
1
≤
n
≤
3
⋅
1
0
5
1 \le n \le 3 \cdot {10^5}
1≤n≤3⋅105
分析
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,…,n−k+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]=i∣∣a[r]=i)&&(l≤j≤rmina[j]=i),1<i<n,此时对于
k
=
n
−
i
+
1
k=n-i+1
k=n−i+1,
b
b
b数组满足要求。注意对于只满足
min
l
≤
j
≤
r
a
[
j
]
=
i
{\mathop {\min }\limits_{l \le j \le r} a[j] = i}
l≤j≤rmina[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;
}