Luogu3871 [TJOI2010]中位数 题解
题目链接
看到题解里好多大佬用二分,splay,树状数组,优先队列等高级数据结构,然而本蒟蒻实在是渣,所以只能用最简单的纯vector写。
(个人觉得比大佬们写的简单)
C++中stl表真的方便,其中向量vector支持数组中间插入:
v.insert(v.begin()+i,a);
/*
v.begin()指v数组头地址,v.begin()+i相当于v[i],a即插入的值
*/
先发出我普通数组纯暴力30分的代码来揭露普通数组的害处
//30分的烂代码就不多加注释了
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
using namespace std;
long long m,n,a[110001];
string f;
int main(){
scanf("%lld",&n);
for(long long i=1;i<=n;i++)scanf("%lld",&a[i]);
scanf("%lld",&m);
for(long long i=1;i<=m;i++){
cin>>f;
if(f=="add")scanf("%lld",&a[++n]);//将数直接加入数组尾
else{
sort(a+1,a+n+1);//每次sort不超时才怪
if(n%2)printf("%lld\n",a[(long long)ceil(n/2.0)]);
else printf("%lld\n",min(a[n/2],a[n/2+1]));
}
}
}
废话完了可以开始正文了
首先读入向量数组,sort排序:
scanf("%lld",&n);
for(long long i=0; i<n; i++) {
scanf("%lld",&a); //读入a
v.push_back(a); //将a放入v中
}
sort(v.begin(),v.end()); //排序,保证v为单调递增
以下本题核心:
将数插入向量v中,普通数组只支持修改查询,插入需每次sort排序或使用手工链表,sort排序过慢,链表调试不够方便,于是vector便闪亮登场(此处应有掌声)。
读入数据a,从头访问vector,在第一个大于a的位置前插入b,这样可以保证vector一直为单调递增,不需每次排序。同时应记录vector的长度n(话说好像用v.size()调整一下貌似也可以),n初始值为原始vector的长度。代码:
scanf("%lld",&a);
n++; //v的长度++
for(int i=0; i<n; i++) { //从头访问
if(v[i]>a) { //一旦找到第一个比a大的元素
v.insert(v.begin()+i,a);//将a插入v中
break; //退出循环
}
}
访问处在中间位置的数。若序列长度为偶数,则指处在中间位置的两个数中较小的那个,由于本vector数组从v[0]开始,所以记录的长度n-1才为要访问的点,即vector中第n个值为v[n-1]:
if(n%2) //若为奇数
printf("%lld\n",v[(long long)ceil(n/2.0)-1]);
//奇数除以2不为整数
//但注意C++中整数除以整数恒得整数,所以要除以实数2.0
//而数组下标必须为整型,所以要强制类型转换
else
printf("%lld\n",min(v[n/2-1],v[n/2]));
//输出中间位置两个数中较小者
所以组合起来AC总代码:
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<vector>
using namespace std;
long long a,m,n;
string f;
vector<long long>v;
int main() {
v.reserve(200010); //保留空间,使v最大长度为200010,节省内存
scanf("%lld",&n);
for(long long i=0; i<n; i++) {
scanf("%lld",&a);
v.push_back(a);
}
sort(v.begin(),v.end());
scanf("%lld",&m);
for(long long i=1; i<=m; i++) {
cin>>f; //读入字符串f
if(f=="add") { //若字符串f为add则插入v中
scanf("%lld",&a);
n++;
for(int i=0; i<n; i++) {
if(v[i]>a) {
v.insert(v.begin()+i,a);
break;
}
}
} else { //若f为mid输出中位数
if(n%2)
printf("%lld\n",v[(long long)ceil(n/2.0)-1]);
else
printf("%lld\n",min(v[n/2-1],v[n/2]));
}
}
return 0;
}
PS:纯向量模拟,由于存在遍历访问数组和sort排序,复杂度最好情况为O(nm),最差可到O(nmlogn),代码跑的比较慢,qwq
但是好理解就足够了,对吧(其实是数据太水了QWQ)