D. Unique Median【Codeforces Round 997 (Div. 2)】

D. Unique Median

在这里插入图片描述

思路:

长度为奇数的一定是好数组,很容易相当找长度为偶数中的好数组数量,但是过于复杂。正向解决困难的情况下可以尝试反向思考,即找长度为偶数的非好数组数量,总答案就等于 n*(n+1)/2 - 非好数组数量。
每次枚举一个 i i i 作为较大的那个中位数,那么这个数组不好的条件为 大于等于i的数的数量等于小于i的数的数量。如果将数组a中大于等于i的数记为1,小于i的数记为-1,得到一个新的数组b,那么不好的条件即为数组中 ∑ b [ i ] = 0 \sum b[i] = 0 b[i]=0
记b的前缀和为pre,那么区间 l − r l-r lr不好的条件为 p r e [ r ] = p r e [ l − 1 ] pre[r]=pre[l-1] pre[r]=pre[l1]
详见代码

代码:

#include <bits/stdc++.h>
#define endl '\n'
#define int long long
#define pb push_back
#define pii pair<int, int>
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
typedef long long ll;
using namespace std;

const int N = 500100;
int a[N], b[N], pre[N];

void solve(){
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i)
        cin >> a[i];
    int sum = n * (n + 1) / 2;
    for (int i = 1; i <= 10; ++i){ // 遍历i,枚举中位数中较大的那个
        map<int, int> mp; // 记录前缀和出现次数
        for (int j = 1; j <= n; ++j)
            if (a[j] >= i)
                b[j] = 1;
            else
                b[j] = -1;
        for (int j = 1; j <= n; ++j)
            pre[j] = pre[j - 1] + b[j];
        int pos = 0;// 单向指针,一直向右走到j-1 
        for (int j = 1; j <= n; ++j)
        {
            if (a[j] == i)  //如果a[j]等于当前枚举的i时,这样能确保不重复统计
                while (pos < j)  //pos移动到j-1来,并统计pre出现次数,存在mp中
                    ++mp[pre[pos++]];
            sum -= mp[pre[j]];  //pre[j]在1到j-1的出现次数即mp[pre[j]] 为前面这一段的非好子数组数,从总ans中减去
        }
    }
    cout << sum << '\n';
}

signed main(){
    cin.tie(0)->ios::sync_with_stdio(0);
    int T = 1;
    cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值