H. Sakurako's Test

H. Sakurako's Test

Sakurako will soon take a test. The test can be described as an array of integers n and a task on it:

Given an integer x, Sakurako can perform the following operation any number of times:

  • Choose an integer i (1in) such that aix;
  • Change the value of ai to aix.

Using this operation any number of times, she must find the minimum possible median of the array a.

Sakurako knows the array but does not know the integer x. Someone let it slip that one of the q values of x will be in the next test, so Sakurako is asking you what the answer is for each such x.

The median of an array of length n is the element that stands in the middle of the sorted array (at the n+22-th position for even n, and at the n+12-th for odd)

Input

The first line contains one integer t (1t104)  — the number of test cases.

The first line of each test case contains two integers n and q (1n,q105)  — the number of elements in the array and the number of queries.

The second line of each test case contains n integers a1,a2,,an (1ain)  — the elements of the array.

The following q lines each contain one integer x (1xn).

It is guaranteed that the sum of n across all test cases does not exceed 105. The same guarantee applies to the sum of q across all test cases.

Output

For each test case, output q integers  — the answer for each query.

Example

Input

2
5 5
1 2 3 4 5
1
2
3
4
5
6 3
1 2 6 4 1 3
2
1
5

Output

0 1 1 1 2 
1 0 2 

 

解题思路

  首先要知道当集合中的元素越小,那么集合中元素的中位数越小。因此我们应该让一个数尽可能减去 x,最后得到 ai:=aimodx。对于固定的 x,在执行操作后中位数就已经确定了,即第 n2+1 小的数。但由于需要对每个 aix,直接暴力做的话时间复杂度是 O(qn)

  不妨换个思虑,对于每个 x 二分出最小的中位数(初始时二分的左右端点分别为 0x1),假设二分点为 m,那么余数不超过 m 的元素个数如果至少为 n2+1,则说明中位数小于等于 m。因此现在问题是如何快速求出模 x 后不超过 m 的元素数量。

  把每个元素看作是 qx+r,(qN,0r<x) 的形式,因此满足模 x 不超过 m 的数可以表示成区间 [kx,kx+m]。由于 ain,因此 knx。枚举 k,累加值在 [kx,kx+m] 内的元素数量(可以用权值前缀和作差得到),最后判断累加的值是否不小于 n2+1 即可。

  利用调和级数的性质,我们直接预处理出 x[1,n] 的答案。时间复杂度就是 x=1nnxlogxnlog2n。最后 O(1) 查询即可。

  AC 代码如下,时间复杂度为 O(nlog2n)

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 1e5 + 5;

int n, m;
int s[N], ans[N];

bool check(int x, int m) {
    int cnt = 0;
    for (int i = 0; i <= n; i += x) {
        cnt += s[min(n, i + m)] - s[i - 1];
    }
    return cnt >= n / 2 + 1;
}

void solve() {
    cin >> n >> m;
    memset(s, 0, n + 1 << 2);
    for (int i = 0; i < n; i++) {
        int x;
        cin >> x;
        s[x]++;
    }
    for (int i = 1; i <= n; i++) {
        s[i] += s[i - 1];
    }
    for (int i = 1; i <= n; i++) {
        int l = 0, r = i - 1;
        while (l < r) {
            int mid = l + r >> 1;
            if (check(i, mid)) r = mid;
            else l = mid + 1;
        }
        ans[i] = l;
    }
    while (m--) {
        int x;
        cin >> x;
        cout << ans[x] << ' ';
    }
    cout << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    
    return 0;
}

 

参考资料

  Codeforces Round 970 (Div. 3) Editorial:https://codeforces.com/blog/entry/133509

posted @   onlyblues  阅读(210)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!
历史上的今天:
2023-09-02 D. Sorting By Multiplication
2023-09-02 C. Vika and Price Tags
2022-09-02 环形石子合并
Web Analytics
点击右上角即可分享
微信分享提示