题解:P11839 [USACO25FEB] The Best Lineup S
题解:P11839 [USACO25FEB] The Best Lineup S
Preface
提供一种
视频题解。
9 场银组,我终于 Au 了。分数线才 700 分?这应该是 2020 年以来最简单的一场银组了。
Problem Statement
P11839。 有一个序列,给你一次操作改变原序列顺序的机会,让你从前往后每个数可以选或不选,构造一个字典序最大的序列。
Solution
首先,由于是要最大化字典序,显然是从最大的开始,能选就选。
因此对原数组按照元素大小为第一关键字降序排序,原位置为第二关键字升序排序(至于为什么等会解释)。然后就贪心的从前往后能选就选(因为字典序吗,前面更优就总体更优)。
如何判断能不能选呢?记录一个
此时发现对于一个每一个元素
但是我们只有一次操作,怎么确保把它用到最优的
但别忘了最后还有两个元素相同的情况,这种情况下我们之所以要以初始位置为第二关键字升序排序就是为了不会在两个相同的元素上因为位置反了而浪费掉操作的机会。
Code
实现非常简单,记录
#include<bits/stdc++.h>
#define int long long
using namespace std;
int T1, n, a[200005];
pair<int, int> val[200005];
int cmp(pair<int, int> &x, pair<int, int> &y){
if(x.first != y.first)return x.first > y.first;
else return x.second < y.second;
//if they have different value, return bigger one, otherwise
//return the one that appeared earlier
}
signed main(){
cin>>T1;
while(T1--){
cin>>n;
for(int i = 1; i <= n; i++){
cin>>a[i];
val[i].first = a[i];
val[i].second = i;
}
int ma = 0, ma2 = 0, moved = 0, outp = 0;
sort(val + 1, val + n + 1, cmp);
for(int i = 1; i <= n; i++){
if(val[i].second > ma){
ma2 = ma;
ma = val[i].second;
if(outp)cout<<" "<<val[i].first;
else cout<<val[i].first;
outp = 1;
}else if(val[i].second > ma2 && !moved){
ma = val[i].second;
//we move ma
if(outp)cout<<" "<<val[i].first;
else cout<<val[i].first;
outp = 1;
moved = 1;
// cout<<val[i].second<<endl;
}
}
cout<<endl;
}
return 0;
}
赛时代码,略丑。
After thought
这场真的有点简单了,我都怀疑 USACO 是不是故意放水,打算再加一个组呀?就像 2015 年加白金之前放水那样。
求赞。