Codeforces Round #759 (Div. 2, based on Technocup 2022 Elimination Round 3) 个人题解
比赛链接:Codeforces Round #759 (Div. 2, based on Technocup 2022 Elimination Round 3)
A题 Life of a Flower
题目大意:
给出一颗植物和一个长度为 \(n\) 的 \(01\) 串, \(0\) 表示当天不浇水, \(1\) 表示当天浇水,并且满足连续浇水 \(+5\) ,单次浇水 \(+1\) ,两天不交直接死亡
问最后植物高度
思路解析:
按天模拟即可
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define endl '\n'
#define pii pair<int,int>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int maxn=1e6+5;
int a[maxn];
int main(){
IOS
int t;
cin>>t;
while(t--){
int n,ok=0;
ll ans=1;
cin>>n;
int now=1;
for(int i=1;i<=n;i++)cin>>a[i];
ans+=a[1];
for(int i=2;i<=n;i++){
if(a[i]==1){
if(a[i-1])ans+=5;
else ans++;
}else {
if(a[i-1]==0)ok=1;
}
}
if(ok)cout<<-1<<endl;
else cout<<ans<<endl;
}
}
B题 Array Eversion
题目大意:
给出一个长度为 \(n\) 的序列 \(a\) ,每一次我们选择 \(a_n\) ,把小于它的数放在他左边,大于的放在右边,并且不改变元素的相对位置,问最小变换几次后序列稳定,即不再发生变化
思路解析:
我们很容易会想到,在什么情况下他才是稳定的:
显然,当 \(a_n\) 为序列的最大值时,序列变为稳定,因为 \(a_n\) 已经是序列最大值了,他应该在的位置就是 \(a_n\) ,所以我们的问题转化成了最少操作几次能使序列的最后一个元素是整个序列的最大值
对于转化后的问题,我们可以从后往前处理序列:
那么我们每一次操作就会有以下的步骤:
如果序列尾的元素不是最大值,那么我们就从序列尾弹出这个元素,另外如果下一个成为序列尾的元素不大于弹出的序列尾,那么它对我们的答案计算是没有用的,一并将他弹掉(因为他一定是会被放在重组序列的左半边),重复这样的操作直到下一个大于他的数出现
我们可以使用 \(deque\) 或者 \(stack\) 来对序列尾进行操作
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define endl '\n'
#define pii pair<int,int>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int maxn=1e6+5;
int a[maxn],b[maxn];
int main(){
IOS
int t;
cin>>t;
while(t--){
int n;
cin>>n;
int top=-5;
stack<int>q;
for(int i=1;i<=n;i++){
cin>>a[i];
top=max(top,a[i]);
q.push(a[i]);
}
int ans=0;
while(q.top()!=top){
int tt=q.top();
q.pop();
ans++;
while(q.top()<=tt)q.pop();
}
cout<<ans<<endl;
}
}
C题 Minimize Distance
题目大意:
在数轴上有 \(n\) 个点,你需要把每一个点都放上一个包,你从 \(0\) 点出发,每次你可以从 \(0\) 点带 \(k\) 个包出发,问放满包至少需要走多少路程
特别的,在最后一个包被放置后你不需要回到 \(0\) 点
思路解析:
我们会发现我们每一次放 \(k\) 个包后都要回起点补充包,所以我们贪心的去向左右放置包,左右两边每 \(k\) 个点回来一次(我们会发现从远到近放是最优的),计算路程即可
但是我们发现答案是比正确答案大一点的,那是因为我们还需要减掉最后一次不回来的情况:
显然我们需要以最远的那个包作为终点才会让我们的距离更短
AC代码:
#include<bits/stdc++.h>
#include <queue>
using namespace std;
typedef long long ll;
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define endl '\n'
#define pii pair<int,int>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int maxn=1e6+5;
int main(){
IOS
int t;
cin>>t;
while(t--){
int n,k;
cin>>n>>k;
priority_queue<ll>a,b;
for(int i=1;i<=n;i++){
int x;
cin>>x;
if(x>0)a.push(x);
else b.push(-x);
}
ll ans=0,tot=0,sum=0;
while(a.size()){
tot=max(tot,a.top());
ans+=a.top()*2;
int tmp=k;
while(a.size()&&tmp--)a.pop();
}
while(b.size()){
sum=max(sum,b.top());
ans+=b.top()*2;
int tmp=k;
while(b.size()&&tmp--)b.pop();
}
cout<<ans-max(tot,sum)<<endl;
}
}
D题 Yet Another Sorting Problem
题目大意:
给出一个序列,你可以进行如下操作:
任意选择下标 \(i,j,k\) 的元素,对元素进行交换,即 \(i->j->k->i\) 交换,问能否经过若干操作使得序列递增,若可以输出 \(YES\) ,否则输出 \(NO\)
思路解析:
我们会发现本题与逆序对有着千丝万缕的联系(划重点)
首先我们考虑一种特殊情况:当出现了两个重复的数时,我们可以利用这两个数将任意元素转移到任意位置(手搓一下就知道了),所以答案一定是 \(YES\)
那么对于一个序列来说,显然如果一个序列的逆序对数量为偶数是,答案一定是 \(YES\) ,否则就是 \(NO\)
逆序对可以用归并或者树状数组实现
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define endl '\n'
#define pii pair<int,int>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int maxn=1e6+5;
int n,a[maxn],tmp[maxn];
ll merge_sort(int q[], int l, int r)
{
if (l >= r) return 0;
int mid = l + r >> 1;
ll res = merge_sort(q, l, mid) + merge_sort(q, mid + 1, r);
int k = 0, i = l, j = mid + 1;
while (i <= mid && j <= r)
if (q[i] <= q[j]) tmp[k ++ ] = q[i ++ ];
else
{
res += mid - i + 1;
tmp[k ++ ] = q[j ++ ];
}
while (i <= mid) tmp[k ++ ] = q[i ++ ];
while (j <= r) tmp[k ++ ] = q[j ++ ];
for (i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j];
return res;
}
int main(){
IOS
int t;
cin>>t;
while(t--){
cin>>n;
int ok=0;
map<int,int>vis;
for(int i=1;i<=n;i++){
cin>>a[i];
if(vis[a[i]])ok=1;
vis[a[i]]=1;
}
if(ok){
cout<<"YES"<<endl;
continue;
}
if(merge_sort(a, 1, n)%2==0)ok=1;
if(ok)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
E题 Frequency Queries
题目大意:
不会(晕)
思路解析:
我好菜QAQ
AC代码:
//假装这里有代码
F题 Non-equal Neighbours
题目大意:
给出长度为 \(n\) 的序列 \(a\) ,构造等长序列 \(b\) ,满足 \(1<=b_i<=a_i\) , \(b_i \not= b_i+1\)
输出 \(b\) 的方案数 \(mod 998244353\)
思路解析:
Atcoder ARC115_E 原题
DP balabala......
当然小飞龙也是不会滴,有空补一补 (下次一定)
AC代码:
//假装这里有代码