Codeforces 1005E1&2 Median on Segments (General Case & Permutations Edition)

E1

想到的O(n)做法,因为m只会出现一次,所以subarray里必须包括m。可以想像合法的subarray是m左边一个连续区间+m+m右边一个连续区间组成。然后把左区间预处理,枚举右区间就行了。(根据性质:一个subarray的median是m,那说明有0个数净比m大,或有1个数净比m大)【净大指的是2个比m小,1个比m大,算-1个比m净大】

 1 #include<iostream>
 2 #include<map>
 3 using namespace std;
 4
 5 long long a[200005],index,ans;
 6 map<int,int> mp;
 7
 8 int main(){
 9     int n,m; cin>>n>>m;
10     for(int i=1;i<=n;i++){
11         scanf("%lld",a+i);
12         if(a[i]==m) index=i;
13     }
14
15     int count=0;
16     mp[0]=1;
17     for(int i=index-1;i>=1;i--){
18         if(a[i]>m) { count++; mp[count]++; }
19         else { count--; mp[count]++; }
20     }
21
22     count=0;
23     for(int i=index;i<=n;i++){
24         if(a[i]>m) count++;
25         else if(a[i]<m) count--;
26         //cout<<count<<" "<<mp[-count]<<" "<<mp[-count+1]<<endl;
27         ans+=mp[-count]+mp[-count+1];
28     }
29
30     cout<<ans;
31
32     return 0;
33 }

E2

这个做法与上一个完全不同,nlogn做法。

greatCount(m)返回有多少个subarray使得其median大于等于m,这样答案就是greatCount(m)-greatCount(m+1)

一个subarray的median要想大于等于m,那得有至少一个数净大于等于m。

维护一个sum[i]数组,代表1-i中有多少个数净大于等于m【就是大于等于m的数量减去小于m的数量】,那所有median大于m的区间都是 i>j, sum[i]-sum[j]>0 => sum[i]>sum[j]的问题。可以按值插入树状数组维护。

注意一下sum[i]里面可能是负数,所以在add的时候可以加上个大常数这样就变成正的了。

 1 #include<iostream>
 2 #include<map>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<cstring>
 6 #define lowbit(x) x&(-x)
 7 using namespace std;
 8
 9 int a[200005],s[200005],n;
10 int c[400005];
11
12 void add(int index,int dx){
13     for(;index<=n+200000;index+=lowbit(index))    c[index]+=dx;
14 }
15
16 int getSum(int n1){
17     int ans=0;
18     for(;n1>0;n1-=lowbit(n1)) ans+=c[n1];
19     return ans;
20 }
21
22 long long greatCount(int m){//有多少个segment使得它的median大于等于m
23     //枚举segment的结尾
24     memset(c,0,sizeof(c));
25     long long result=0,sum=0;
26     //要想median大于m,sum[i]>sum[j]
27     //i>j, sum[i]>sum[j]
28     add(200000,1);//0-i
29     for(int i=1;i<=n;i++){
30         if(a[i]>=m) sum+=1;
31         else sum-=1;
32
33         if(i!=n) add(sum+200000,1);
34         result+=getSum(sum-1+200000);
35     }
36     return result;
37 }
38
39
40 int main(){
41     int median; cin>>n>>median;
42     for(int i=1;i<=n;i++) scanf("%d",a+i);
43
44     cout<<greatCount(median)-greatCount(median+1);
45
46     return 0;
47 }

原文地址:https://www.cnblogs.com/ZhenghangHu/p/9313271.html

时间: 2024-08-30 11:29:11

Codeforces 1005E1&2 Median on Segments (General Case & Permutations Edition)的相关文章

Codeforces #496 E1. Median on Segments (Permutations Edition)

http://codeforces.com/contest/1005/problem/E1 题目 https://blog.csdn.net/haipai1998/article/details/80985281  原博客 对样例1: 5 42 4 5 3 1 m=4,所以下标pos=2: 从pos往右遇到比m大的就cnt++,遇到小的就cnt--: 刚开始cnt=0;  mp[cnt]++ 于是从pos开始到 n:   mp[0]=1,   mp[1]=1,   mp[0]=2 ,   mp[

Median on Segments (Permutations Edition)

E1. Median on Segments (Permutations Edition) 参考:CF1005E1 Median on Segments (Permutations Edition) 思维 中位数为m的条件为,在那一段中,小于 m 的数的个数为 x 个,大于 m 的数有 y 个,要满足条件x==y||x==y-1. 因为不可能每一次都去统计有多少个大于的多少个小于的,所以我们要预处理一下,借此来降低复杂度 map<int,int> ma; int cnt=0; for(int

Codeforces Round #485 (Div. 2) E. Petr and Permutations

Codeforces Round #485 (Div. 2) E. Petr and Permutations 题目连接: http://codeforces.com/contest/987/problem/E Description Petr likes to come up with problems about randomly generated data. This time problem is about random permutation. He decided to gene

Codeforces Round #310 (Div. 1)——A水——Case of Matryoshkas

Andrewid the Android is a galaxy-famous detective. He is now investigating the case of vandalism at the exhibition of contemporary art. The main exhibit is a construction of n matryoshka dolls that can be nested one into another. The matryoshka dolls

Educational Codeforces Round 10 D. Nested Segments (树状数组)

题目链接:http://codeforces.com/problemset/problem/652/D 给你n个不同的区间,L或者R不会出现相同的数字,问你每一个区间包含多少个区间. 我是先把每个区间看作整体,按照R从小到大排序.然后从最小的R开始枚举每个区间,要是枚举到这个区间L的时候,计算之前枚举的区间有多少个Li在L之后,那么这些Li大于L的区间的数量就是答案.那我每次枚举的时候用树状数组add(L , 1) 说明在L这个位置上出现了区间,之后枚举的时候计算L之前的和,然后i - 1 -

CF Educational Codeforces Round 10 D. Nested Segments 离散化+树状数组

题目链接:http://codeforces.com/problemset/problem/652/D 大意:给若干个线段,保证线段端点不重合,问每个线段内部包含了多少个线段. 方法是对所有线段的端点值离散化,按照左端点从大到小排序,顺着这个顺序处理所有线段,那么满足在它内部的线段一定是之前已经扫到过的.用树状数组判断有多少是在右端点范围内. 1 #include <iostream> 2 #include <vector> 3 #include <algorithm>

【CodeForces】901 C. Bipartite Segments

[题目]C. Bipartite Segments [题意]给定n个点m条边的无向连通图,保证不存在偶数长度的简单环.每次询问区间[l,r]中包含多少子区间[x,y]满足只保留[x,y]之间的点和边构成的图是一个二分图. [算法]Tarjan缩点(找环) [题解]如果两个奇数长度的环相交,会得到一个偶数长度的简单环.所以原图是不存在偶数长度环的仙人掌(每条边只属于一个简单环). 二分图的定义:一个图是二分图当且仅当不存在奇数长度的环.在当前仙人掌上,二分图实际上要求选择的点不存在环. 也就是对于

codeforces 430 A Points and Segments (easy)

题意:给出n个点,m个区间,需要给这些点涂上蓝色或者红色,使得每个区间里面的点的红色的点的个数与蓝色的点的个数的差值小于1 唉,题目的标题就标注了一个easy= = 最开始做的时候对点还有区间都排序了,模拟来做,可是错了 后来发现不管区间怎么样,只要红色和蓝色交替涂色, 就一定能满足“使得每个区间里面的点的红色的点的个数与蓝色的点的个数的差值小于1 ”这个条件 有点像上次做的cf交替输出奇数偶数那个A题 1 #include<iostream> 2 #include<cstdio>

E1. Median on Segments (Permutations Edition)

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 16.0px Menlo; color: #008400; background-color: #ffffff } p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; background-color: #ffffff; min-height: 14.0px } n个数字 不重复 给你一个m 然后问你有多少个区间的中位数是m 奇数