F. MEX vs MED (2000‘ 数学)

Codeforces Round #828 (Div. 3) F. MEX vs MED

原题链接

time limit per test 1 second

memory limit per test 256 megabytes

题面

You are given a permutation p 1 , p 2 , … , p n p_1,p_2,…,p_n p1,p2,,pn of length n n n of numbers 0 , … , n − 1 0,…,n−1 0,,n1. Count the number of subsegments 1 ≤ l ≤ r ≤ n 1≤l≤r≤n 1lrn of this permutation such that m e x ( p l , p l + 1 , … , p r ) > m e d ( p l , p l + 1 , … , p r ) mex(p_l,p_{l+1},…,p_r)>med(p_l,p_{l+1},…,p_r) mex(pl,pl+1,,pr)>med(pl,pl+1,,pr).

m e x mex mex of S S S is the smallest non-negative integer that does not occur in S S S. For example:

  • m e x ( 0 , 1 , 2 , 3 ) = 4 mex(0,1,2,3)=4 mex(0,1,2,3)=4
  • m e x ( 0 , 4 , 1 , 3 ) = 2 mex(0,4,1,3)=2 mex(0,4,1,3)=2
  • m e x ( 5 , 4 , 0 , 1 , 2 ) = 3 mex(5,4,0,1,2)=3 mex(5,4,0,1,2)=3

m e d med med of the set S S S is the median of the set, i.e. the element that, after sorting the elements in non-decreasing order, will be at position number $ \left \lfloor \dfrac{|S|+1}{2}\right\rfloor$ (array elements are numbered starting from 1 and here ⌊ v ⌋ ⌊v⌋ vdenotes rounding v v v down.). For example:

  • m e d ( 0 , 1 , 2 , 3 ) = 1 med(0,1,2,3)=1 med(0,1,2,3)=1
  • m e d ( 0 , 4 , 1 , 3 ) = 1 med(0,4,1,3)=1 med(0,4,1,3)=1
  • m e d ( 5 , 4 , 0 , 1 , 2 ) = 2 med(5,4,0,1,2)=2 med(5,4,0,1,2)=2

A sequence of nn numbers is called a permutation if it contains all the numbers from 0 0 0 to n − 1 n−1 n1 exactly once.

翻译

给定一个 0... n − 1 0...n-1 0...n1 的排列,求有多少个区间 [ l , r ] [l,r] [l,r] 满足 m e x ( p l . . . p r ) > m e d ( p l . . . p r ) mex(p_l...p_r)>med(p_l...p_r) mex(pl...pr)>med(pl...pr)

其中 m e x mex mex的含义为区间中没有出现过的最小非负数 ; m e d med med 的含义为区间中排名不超过一半的最大数字。

题解

x x x 是某个区间的 m e x mex mex 的条件:该区间中 0... x − 1 0...x-1 0...x1 都出现了,但是 x x x 没有出现。

我们记 l , r l,r l,r 分别为 0... x − 1 0...x-1 0...x1 的所有数字在排列中出现的最靠前和最靠后的位置,记 x x x 出现的位置为 p o s pos pos

注意到一个性质:

l , r l,r l,r x x x 的同侧,则 x x x 为某些区间的 m e x mex mex;否则, x x x 一定不可能是某些区间的 m e x mex mex

简要说明:

l , r l,r l,r x x x 的同侧,则 [ l , r ] [l,r] [l,r] 中出现了小于 x x x 的所有数字,但是没有出现 x x x, 所以 [ l , r ] [l,r] [l,r] m e x mex mex 值为 x x x ;反之如果 l , r l,r l,r x x x 的两侧,则任何一个区间都不可能同时包含小于 x x x 的所有数字却不包含 x x x

注意到第二个性质:

满足题意要求的 m e x > m e d mex>med mex>med 的区间,区间长度 l e n len len 一定不超过 2 × m e x 2\times mex 2×mex

简要说明:

区间中一定包含 0... m e x − 1 0...mex-1 0...mex1 已经占用了 m e x mex mex 个位置,而剩余的元素一定都是大于 m e x mex mex 的。如果剩余的元素多于 m e x mex mex 个,那么排名居中的数字一定会大于 m e x mex mex

进而有了第三个性质:

如果一个区间长度为 l e n len len ,并且包含了 0... ⌊ l e n − 1 2 ⌋ 0...\left\lfloor \dfrac{len-1}{2}\right\rfloor 0...2len1 的全部数字,那么这个区间一定是满足要求的。相反如果这个区间没有包含 1... ⌊ l e n − 1 2 ⌋ 1...\left\lfloor \dfrac{len-1}{2} \right\rfloor 1...2len1 中的某个数字, 那么这个区间一定是不满足要求的。

证明:

如果包含了 0... ⌊ l e n − 1 2 ⌋ 0...\left\lfloor \dfrac{len-1}{2} \right\rfloor 0...2len1 的所有数字,那么该区间的 m e x mex mex 至少为区间中第 ⌊ l e n − 1 2 ⌋ + 2 \left\lfloor \dfrac{len-1}{2} \right\rfloor+2 2len1+2 大的数字。而该区间的 m e d med med 为第 ⌊ l e n + 1 2 ⌋ \left\lfloor \dfrac{len+1}{2} \right\rfloor 2len+1 大的数字。

由于 ⌊ l e n − 1 2 ⌋ + 2 > ⌊ l e n − 1 2 ⌋ \left\lfloor \dfrac{len-1}{2} \right\rfloor +2 > \left\lfloor \dfrac{len-1}{2} \right\rfloor 2len1+2>2len1,因此一定有 m e x > m e d mex>med mex>med

反之同理。

由第三个性质就直接得到了解法:

从小到大枚举 l e n len len ,并不断更新包含 0... ⌊ l e n − 1 2 ⌋ 0...\left\lfloor \dfrac{len-1}{2} \right\rfloor 0...2len1所有数字的左右边界 l , r l,r l,r。如果这个区间长度大于 l e n len len 那么该长度下无解,否则该长度下包含区间 l , r l,r l,r 的所有区间都是满足要求的。

另外,在更新 l , r l,r l,r 的过程中还有一点小细节,见代码。

#include<bits/stdc++.h>
using namespace std;

#define int long long

/******************************************************************/
/******************************************************************/
/**************************以下是做题代码***************************/

const int N = 5e5 + 7;
int  pos[N], n, x, l, r, res;

void SolveTest() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> x;
        pos[x] = i;
    }
    l = r = pos[0];
    res = 1;//长度为1的区间只有单个的0满足要求

    //枚举区间的长度
    for (int len = 2; len <= n; len++) {

        // me为该区间长度下,满足要求的最小的mex值
        int me = (len - 1) / 2;

        //所有满足条件的区间:长度为len,包含子区间[l,r]
        l = min({l, pos[me], n + 1 - len});
        r = max({r, pos[me], len});
        res += max(0ll, len - (r - l));
    }
    cout << res << '\n';
}

/**************************以上是做题代码***************************/
/******************************************************************/
/******************************************************************/

signed main() {
#ifdef CQLOCAL
    freopen("C:/Users/20824/Desktop/C++代码/in.txt", "r", stdin);
    freopen("C:/Users/20824/Desktop/C++代码/out.txt", "w", stdout);
#endif
    int TestCase = 1;
    cin >> TestCase;
    for (int i = 1; i <= TestCase; i++) {
        SolveTest();
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值