A. Greatest Convex
题意
题目链接
找出最大的
x
x
x
,其中
1
≤
x
<
k
1≤x<k
1
≤
x
<
k
,使得
x
!
+
(
x
−
1
)
!
x!+(x−1)!
x
!
+
(
x
−
1
)!
能整除
k
k
k
。
思路
令
x
=
k
−
1
x=k-1
x
=
k
−
1
,则
(
k
−
1
)
!
+
(
k
−
2
)
!
=
(
k
−
1
)
(
k
−
2
)
!
+
(
k
−
2
)
!
=
k
(
k
−
2
)
!
(k-1)!+(k−2)!=(k-1)(k−2)!+(k−2)!=k(k-2)!
(
k
−
1
)!
+
(
k
−
2
)!
=
(
k
−
1
)
(
k
−
2
)!
+
(
k
−
2
)!
=
k
(
k
−
2
)!
,当
k
≥
2
k≥2
k
≥
2
时,输出
k
−
1
k-1
k
−
1
即可。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 32768 + 5;
ll k,t;
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>t;
while(t--){
cin>>k;
cout<<k-1<<endl;
}
return 0;
}
B. Quick Sort
题意
题目链接
给出一个排列和一个整数
k
k
k
,每次操作中,你可以从排列中取出
k
k
k
个不同的元素,将它们从小到大排序后放到排列末尾。求使得排列从小到大排好序的最小操作数。
思路
统计排列中没有按照从小到大排好序的元素的个数,即需要被操作的元素最少有多少个。因为每次操作
k
k
k
个,那么答案就是这些元素的数量除以
k
k
k
再向上取整。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 1e5 + 5;
ll t, p[maxn];
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>t;
while(t--){
ll n,k;
cin>>n>>k;
for(ll i=1;i<=n;i++)cin>>p[i];
ll cur = 1, ans = 0;
for(ll i=1;i<=n;i++){
if(p[i]==cur)cur++;
else ans++;
}
ans = ceil(ans*1.0/k);
cout<<ans<<endl;
}
return 0;
}
C. Elemental Decompress
题意
题目链接
给出一个数组
a
a
a
,请你构造两个排列
p
p
p
和
q
q
q
,使得对于每一个
1
≤
i
≤
n
1≤i≤n
1
≤
i
≤
n
,都有
m
a
x
(
p
i
,
q
i
)
=
a
i
max(p_{i},q_{i})=a_{i}
ma
x
(
p
i
,
q
i
)
=
a
i
。
思路
首先,这个数组中不可能超过2次出现同一个数,否则就构造不出来。
我们可以对数组进行结构体排序,从小到大分析每一个元素对应的
p
i
p_{i}
p
i
和
q
i
q_{i}
q
i
。
如果数组中的这个元素出现了2次,那么就分别为两个排列的相应位置添上这个元素;如果数组中的这个元素只出现了1次,那么可以把这个元素对应的
p
i
p_{i}
p
i
和
q
i
q_{i}
q
i
都赋成这个元素自己,那么这个位置的最大值就一定是这个元素。
最后,考虑两个排列中还没有被赋值过的位置,一定是数组中元素出现2次的位置,一个排列已经赋值,另一个排列在这个位置还没有赋值。
我们对两个排列分别从小到大添数。因为之前已经对数组元素从小到大排好序了,那么现在只需要从小到大地看,每个排列中还有哪个数没有用,这个步骤我们之前可以开两个
v
i
s
vis
v
i
s
数组记录。
如果这个数可以用,再看当前这个可以用的最小的数是否比另一个排列中这个位置的元素小,如果是,那就添上这个数,再记录这个数已经用过了。
如果不满足,就一直从小到大查找,直到找到为止,类似于单指针。如果一直找不到,就说明构造不出来。这样遍历添数的时间复杂度仍然是线性的。
最后输出的时候,需要用一个
p
o
s
pos
p
os
数组记录对应的下标映射关系,表示原来
a
[
i
]
.
i
d
a[i].id
a
[
i
]
.
i
d
这个位置上的数对应的在两个排列中的下标是
i
i
i
。那么
p
o
s
[
i
]
pos[i]
p
os
[
i
]
就记录的是数组没有排序时
i
i
i
从小到大对应的在两个排列中的下标。这样就可以正确输出了。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 2e5 + 5;
ll t;
struct node{
ll x, id;
bool friend operator < (const node A, const node B){
return A.x < B.x;
}
}a[maxn];
ll p[maxn],q[maxn],cnt[maxn],pos[maxn];
bool visp[maxn],visq[maxn];
int main(){
//ios::sync_with_stdio(0);
//cin.tie(0),cout.tie(0);
cin>>t;
while(t--){
ll n;
cin>>n;
memset(a,0,sizeof(0));
for(ll i=1;i<=n;i++)visp[i]=false,visq[i]=false,cnt[i]=0;
for(ll i=1;i<=n;i++)p[i]=0,q[i]=0,a[i].x=0,a[i].id=0,pos[i]=0;
for(ll i=1;i<=n;i++)cin>>a[i].x,a[i].id=i;
sort(a+1,a+1+n);
for(ll i=1;i<=n;i++){
cnt[a[i].x]++;
}
bool flag=true;
for(ll i=1;i<=n;i++){
if(cnt[a[i].x]>2){
flag=false;
}
}
if(flag==false){
cout<<"NO"<<endl;
continue;
}
for(ll i=1;i<=n;i++){
if(cnt[a[i].x]==2){
if(visp[a[i].x]==false)p[i]=a[i].x,visp[p[i]]=true;
else q[i]=a[i].x,visq[q[i]]=true;
}
}
for(ll i=1;i<=n;i++){
if(cnt[a[i].x]==1){
p[i]=a[i].x;
q[i]=a[i].x;
visp[p[i]]=true;
visq[q[i]]=true;
}
}
ll curq = 1, curp = 1;
bool f=true;
for(ll i=1;i<=n;i++){
if(p[i]&&q[i]==0){
while(visq[curq]==true||curq>p[i]){
curq++;
if(curq==n+1)break;
}
if(curq==n+1){
f=false;break;
}
q[i]=curq;
visq[curq]=true;
}
else if(p[i]==0&&q[i]){
while(visp[curp]==true||curp>q[i]){
curp++;
if(curp==n+1)break;
}
if(curp==n+1){
f=false;break;
}
p[i]=curp;
visp[curp]=true;
}
}
if(f==false){
cout<<"NO"<<endl;
}
else{
cout<<"YES"<<endl;
for(ll i=1;i<=n;i++){
pos[a[i].id]=i;
}
for(ll i=1;i<=n;i++){
cout<<p[pos[i]]<<" ";
}
cout<<endl;
for(ll i=1;i<=n;i++){
cout<<q[pos[i]]<<" ";
}
cout<<endl;
}
}
return 0;
}
心得
非常遗憾,本来C题赛中我是可以做出来的,最后输出那里调了一会儿没调对,结果比赛就结束了。赛后只用了一会儿就调完了,一交上去就AC了,可以说是非常难受,就差了一点点。以后还是要注意细节。