牛客练习赛87

中位数

(考时脑壳抽了

思路其实很简单
容易知道最终序列长度为\(n-k\)
如果不操作,最小的中位数,即为位置为\((n-k+1)/2\)

我们把删去的数全都往中位数右边的数加即可,中位数不变
\(n-k\)的序列中位数最小值 就是位置\((n-k+1)/2\)

如果\(k==n-1\),原序列和即为所求

记得排序(

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

int t;const int maxn=2e5+10;
int n,k;
int m[maxn];
int main(){
	cin>>t;
	while(t--){
		cin>>n>>k;long long ans=0;
		for(int i=1;i<=n;++i) cin>>m[i],ans+=m[i];
		sort(m+1,m+1+n);
		if(k==n-1) cout<<ans<<endl;
		else cout<<m[(n-k+1)/2]<<endl;
	}return 0;
}

k小数查询

怎么又没读懂题就在那里乱做(我是蒟蒻

给定\([1,n]\)的一个排列

又给定一个数\(x\),找出区间第\(k\)小为\(x\)

就是看区间\([l,r]\)内,有\(k\)个数小于等于\(x\)

根据题意,\(l\)一定小于x这个数的位置,同理\(r\)一定大于x这个数的位置

区间问题,又是静态,则可以考虑前缀和

\(sum[i]\)为前\(i\)个小于\(x\)的数量,那么我们就可以想到用sum来表示满足题意,即\(sum[r]-sum[l-1]=k\),这个区间内有\(k\)个数小于等于\(x\)

处理sum[]很好处理,只需要,令小于\(x\)的数为1,大于\(x\)的数为0,前缀和处理即可

但是根据\(sum[r]-sum[l-1]=k\),是两个端点都在动,暴力枚举直接TLE,考虑只枚举一个端点,

比如只枚举\(r\),我们稍微移项,\(sum[l-1]=sum[r]-k\),此时我们所需的即为sum[l-1]也就是sum[r]-k的个数,

所以统计出\(sum[l-1]\)的数量,而\(l-1 \in [0,pos-1]\),则枚举范围\([0,pos-1]\)(\(sum[0]=1\)因为一定有\(sum[r]-k=0\)),建一个map统计即可

#include<cstdio>
#include<cstring>
#include<iostream>
#include<map>
using namespace std;
#define int long long
int n;const int maxn=2e5+10;
int a[maxn];
map<int ,int >mp;
int x,k;
int pos;
int sum[maxn];
signed main(){
	cin>>n>>x>>k;
	for(int i=1;i<=n;++i)	{
		cin>>a[i];
		if(a[i]==x) pos=i;
		if(a[i]<=x) sum[i]=1+sum[i-1];
		else sum[i]=sum[i-1];
	}
	for(int i=1;i<pos;++i) mp[sum[i]]++;
	int ans=0;mp[0]++;
	for(int i=pos;i<=n;++i) ans+=mp[sum[i]-k];
	cout<<ans<<endl;
	return 0;
}

ZFY AK IOI

posted @ 2021-08-21 15:58  归游  阅读(63)  评论(0编辑  收藏  举报