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代碼:
//假裝這里有代碼