Round 1019(div2)
C - Median Splits(中位数)
题意:把数组分成三段,使得三段的中位数组成的数组的中位数小于等于kkk。
记录sumisum_isumi为前iii个小于等于kkk的个数。然后把满足中位数小于等于kkk的前缀和后缀存下来。
如果最前的前缀和最后的后缀中间至少有一个数,就满足条件了。
否则如果前缀个数或后缀个数大于2也满足条件。再否则讨论两个前缀和两个后缀的情况,如果两个前缀之间中位数小于等于k也满足,后缀同理讨论。
为什么前缀个数大于2就满足条件?
以前缀为例,取最前面的两个合法前缀,如果第一个前缀长度是偶数,那么它到后一个前缀之间的区间也满足,因为它的小于等于k的数正好有一半,所以后一个前缀能满足条件一定是后面出现的小于等于k的数更多。如果第一个前缀长度是奇数,那么下一个满足条件的前缀一定挨着它且这个前缀长度是偶数(因为第一个前缀是最前的,它是奇数那么肯定是单独一个小于等于k的数,那么前两个数就至少有一个数小于等于k了),如果后面还有满足条件的前缀就和上面讨论的一样。所以只要有三个前缀就一定满足。
cpp
void solve(){
int n,k;
cin>>n>>k;
vector<int> a(n+1);
for(int i=1;i<=n;i++){
cin>>a[i];
}
vector<int> pre(n+1),suf(n+10);
for(int i=1;i<=n;i++){
pre[i]=pre[i-1]+(a[i]<=k);
}
for(int i=n;i>=1;i--){
suf[i]=suf[i+1]+(a[i]<=k);
}
vector<int> l,r;
for(int i=1;i<=n;i++){
if(2*pre[i]>=i)l.push_back(i);
}
for(int i=n;i>=1;i--){
if(2*suf[i]>=(n-i+1))r.push_back(i);
}
bool flag =false;
if((l.size()>2)||(r.size()>2)){
flag =true;
}
if(l.size()==2){
if(2*(pre[l[1]]-pre[l[0]])>=(l[1]-l[0])){
flag =true;
}
}
if(r.size()==2){
if(2*(suf[r[1]]-suf[r[0]]) >=(r[0]-r[1])){
flag =true;
}
}
if((!l.empty())&&(!r.empty())){
if(l[0]+1<r[0]){
flag =true;
}
}
if(flag)cout<<"YES\n";
else cout<<"NO\n";
}
D Local Construction(思维+构造)
题意:一开始有一个排列,第奇数时刻把所有 pi<=pi−1且pi<=pi+1p_i<=p_{i-1} 且p_i<=p_{i+1}pi<=pi−1且pi<=pi+1的位置保留,其它删去,偶数时刻则是保留pi>=pi−1与pi>=pi+1p_i>=p_{i-1} 与 p_i>=p_{i+1}pi>=pi−1与pi>=pi+1的位置。现在给出每个位置被删掉的时刻,求一个合法的排列。
模拟,按时刻从小到大枚举,把所有这一时刻的数都取出来,分为−1-1−1的左边和右边的两部分。然后如果是奇数时刻左边从大到小给数,右边从小到大给数(类似于-1是二次函数的那个极值点)。偶数时刻左边从小到大,右边从大到小。这样可以保证这些数一定在这一时刻被删掉。
然后最后剩下的一个数给没被删的那个位置。
cpp
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n + 1);
for (int i = 1; i <= n; ++ i) {
std::cin >> a[i];
}
std::vector<int> ans(n + 1);
int m = *std::max_element(a.begin(), a.end());
int l = 1, r = n;
for (int i = 1; i <= m; ++ i) {
std::vector<int> b[2];
int x = 0;
for (int j = 1; j <= n; ++ j) {
x |= a[j] == -1;
if (a[j] == i) {
b[x].push_back(j);
}
}
reverse(b[1].begin(),b[1].end());
for (auto & j : b[0]) {
if (i & 1) {
ans[j] = r -- ;
} else {
ans[j] = l ++ ;
}
}
for (auto & j : b[1]) {
if (i & 1) {
ans[j] = r -- ;
} else {
ans[j] = l ++ ;
}
}
}
for (int i = 1; i <= n; ++ i) {
if (ans[i] == 0) {
ans[i] = l;
break;
}
}
for (int i = 1; i <= n; ++ i) {
std::cout << ans[i] << " \n"[i == n];
}
}