牛客练习赛87

A-中位数

传送门

题意

给定一个长度为\(n\)的数组,我们进行\(k\)次操作
每次操作的定义如下:

  • 选择两个下标\(i\)\(j\) 我们可以令\(a_i = a_i + a_j\),然后删除\(a_j\)
    求操作之后的数组的中位数的最小值\(\lfloor \frac{len+1}{2} \rfloor\) (len为操作后的数组长度

分析

基于贪心的思想, 对于一个有序数组,我们可以如果通过删数使得数组的中位数最小的话,我们肯定是要尽可能的
把比较大的数字删去.
然后我们考虑删完一个数字造成的结果,使另一个数字加上这个数字.
分两种情况

  • \(len \geq 2\) 的时候,我们可以使从第n-k+1大的数字开始删,之后的数字全部删去,使他们累加到第
    n-k个数字上, 此时我们可以发现中位数永远不可能是第n-k个数字 因此我们输出 \(a[(len+1)/2]\)即可
  • \(len = 1\)的时候,我们可以发现我们删去的所有数字都会累加到仅剩的这个数字上,因此我们输出所有数字的和即可
  • \(len = 0\) 输出 \(0\) 即可

AC_CODE

#include <bits/stdc++.h>

using namespace std;
 
template < typename T >
inline void read(T &x)
{
    x = 0; bool f = 0; char ch = getchar();
    while(!isdigit(ch)){f ^= !(ch ^ 45);ch=getchar();}
    while(isdigit(ch)) x= (x<<1)+(x<<3)+(ch&15),ch=getchar();
    x = f ? -x : x;
}

const int N = 2e5 + 10;
int a[N];

void solve() {
    int n, k;
    read(n), read(k);
    LL ans = 0;
    for(int i = 1; i <= n; i ++ ) {
        read(a[i]);
        ans += a[i];
    }
    sort(a + 1, a + 1 + n);
    int res = n - k; // 长度
    if(res >= 2)
        cout << a[(res + 1) / 2] << endl;
    else {
        if(res == 0) cout << 0 << endl;
        else if(res == 1) cout << ans << endl;
    }
}
 
signed main() 
{
    int T = 1;  scanf("%d",&T);
    while(T -- ) {
        solve();
    }
    return 0;
}

B-k小数查询

题意

给定一个1-n的任意排列, 求出所有的区间\([l,r]\) (\(r-l+1 \geq k\)) 满足
区间内第\(k\)小数是\(x\)

思路

\(x\)肯定属于所有的满足条件的区间 (假设\(x\)的下标为\(idx\)
我们可以把区间分为三种
我们可以记\(l_i\)\([i,idx-1]\)区间内小于\(x\)的数字的数量 \(r_i\)\([idx+1,,i]\) 区间内小于\(x\)的数量

  • \(idx\) 为右边界的区间 所有的\(l_i\)=\(k - 1\)的点的个数
  • \(idx\) 为左边界的区间 所有的\(r_i\)=\(k - 1\)的点的个数
  • \(idx\)为区间内某点且不是边界的区间 所有的\(l_i + r_i = k - 1\)的点对

AC_CODE

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

const int N = 2e5 + 10;
int a[N], ct[N];
int n, x, k, idx;

void solve() {
    scanf("%d%d%d", &n, &x, &k);
    k --;
    for(int i = 0; i < n; i ++ ) {
        scanf("%d", &a[i]);
        if(a[i] == x) idx = i;
    }
    LL ans = 0, cnt = 0;
    for(int i = idx + 1; i < n; i ++ ) {
        cnt += a[i] < x;
        ans += cnt == k;
        ct[cnt] ++;
    }
    cnt = 0;
    for(int i = idx - 1; ~i; i --) {
        cnt += a[i] < x;
        ans += cnt == k;
        if(cnt <= k) ans += ct[k - cnt];
    }
    printf("%lld", ans);
}
 
signed main() 
{
    int T = 1; //scanf("%d",&T);
    while(T -- ) {
        solve();
    }
    return 0;
}
posted @ 2021-08-20 23:11  ccz9729  阅读(80)  评论(0编辑  收藏  举报