牛客练习赛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