D. Unique Median
由题意可以看出奇数长度的数组一定合法,但是偶数长度的数组不一定合法,我们反过来来找非法数组的充要条件,我们观察非法数组
我们可以枚举
对于上述式子我们继续变形,把具有相同个变量的放到一边,得到
接着枚举左端点,又因为我们要保证区间内一定有
由此我们最后用总可能值最后减去每一个位置相对应相反奇偶性的记录值即可。
int a[N] ;
int cnt[N] ;//i个位置之前小于等于k的数的数量
int nex[N] ;//i个位置之后第一个k的位置
int b[N] ;
void solve(){
cin >> n ;
set<int> se ;
for(int i = 1; i <= n ; ++ i){
cin >> a[i] ;
se.insert(a[i]) ;
}
//相同的数组不能重复
ans = (1LL * (1 + n) * n) / 2 ;
//考虑不合法的充要条件 存在k使得偶数长区间, 小于等于k的数的数量等于 区间长度一半
unordered_map<int,int> mp[2] ;
for(auto e : se){//
int k = e ;
for(int i = 1 ; i <= n ; ++ i ){
cnt[i] = cnt[i-1] + (a[i] <= k) ;
}
mp[0].clear() ;
mp[1].clear() ;
nex[n + 1] = n + 1 ;
for(int i = n ; i >= 1 ; -- i){
if(a[i] == k) nex[i] = i ;
else nex[i] = nex[i + 1] ;
}
//非法条件, 偶数区间包含有k并且r - l + 1 = (cnt[r] - cnt[l-1]) * 2,
//根据端点奇偶性分为两桶,左右端点 一奇一偶,保证区间长度为偶数
for(int i = 1; i <= n ; ++ i){//确定右端点, 2 * cnt[r] - r = 2 * cnt[l-1] - l + 1
mp[i&1][cnt[i] * 2 - i] ++ ;
}
int pt = 1;
for(int i = 1; i <= n ; ++ i){//保证区间内有 k 存在
while(pt < nex[i]){// l <= nex[i], r > nex[i] ,保证r在nex[i] 左侧的情况不会进入计算,
mp[pt&1][cnt[pt] * 2 - pt] -- , pt ++ ;
}
ans -= mp[(i^1)&1][cnt[i-1] * 2 - i + 1] ;//
}
}
cout << ans << endl ;
}
Comments NOTHING