Sakurako’s Test
#二分 #值域 #前缀和
题目描述
Sakurako will soon take a test. The test can be described as an array of integers n n n and a task on it:
Given an integer x x x, Sakurako can perform the following operation any number of times:
- Choose an integer i i i ( 1 ≤ i ≤ n 1\le i\le n 1≤i≤n) such that a i ≥ x a_i\ge x ai≥x;
- Change the value of a i a_i ai to a i − x a_i-x ai−x.
Using this operation any number of times, she must find the minimum possible median ∗ ^{\text{∗}} ∗ of the array a a a.
Sakurako knows the array but does not know the integer x x x. Someone let it slip that one of the q q q values of x x x will be in the next test, so Sakurako is asking you what the answer is for each such x x x.
∗ ^{\text{∗}} ∗The median of an array of length n n n is the element that stands in the middle of the sorted array (at the n + 2 2 \frac{n+2}{2} 2n+2-th position for even n n n, and at the n + 1 2 \frac{n+1}{2} 2n+1-th for odd)
输入格式
The first line contains one integer t t t ( 1 ≤ t ≤ 1 0 4 1\le t\le 10^4 1≤t≤104) — the number of test cases.
The first line of each test case contains two integers n n n and q q q ( 1 ≤ n , q ≤ 1 0 5 1\le n,q\le 10^5 1≤n,q≤105) — the number of elements in the array and the number of queries.
The second line of each test case contains n n n integers a 1 , a 2 , … , a n a_1, a_2, \dots, a_n a1,a2,…,an ( 1 ≤ a i ≤ n 1\le a_i\le n 1≤ai≤n) — the elements of the array.
The following q q q lines each contain one integer x x x ( 1 ≤ x ≤ n 1\le x\le n 1≤x≤n).
It is guaranteed that the sum of n n n across all test cases does not exceed 1 0 5 10^5 105. The same guarantee applies to the sum of q q q across all test cases.
输出格式
For each test case, output q q q integers — the answer for each query.
样例 #1
样例输入 #1
2
5 5
1 2 3 4 5
1
2
3
4
5
6 3
1 2 6 4 1 3
2
1
5
样例输出 #1
0 1 1 1 2
1 0 2
解题思路
可以发现, n , x ≤ 1 0 5 n,x \leq 10^5 n,x≤105,因此我们可以直接预处理出所有 x x x的情况。
对于每个 x x x,我们可以二分中位数来 c h e c k check check是否可行,如果可行,那么一定会存在 ≥ ⌈ n 2 ⌉ \geq \lceil \frac{n}{2} \rceil ≥⌈2n⌉的数大于 x x x。
对于每个 a i ≤ n a_i \leq n ai≤n,我们可以使用值域的前缀和数组来记录个数,然后再 c h e c k check check的时候直接暴力枚举所有的 x x x的倍数,记录个数是否满足中位数,这里是调和级数的。
因此,最后的复杂度为 O ( n l o g 2 2 n ) O(nlog^2_2n) O(nlog22n)
代码
void solve() {
int n, q;
cin >> n >> q;
vector<int>a(n + 1), prefix(n + 1);
for (int i = 1; i <= n; ++i) {
std::cin >> a[i];
prefix[a[i]]++;
}
for (int i = 1; i <= n; ++i) {
prefix[i] += prefix[i - 1];
}
vector<int>res(n + 1);
for (int x = 1; x <= n; x++) {
int l = 0, r = x - 1, ans = x - 1;
while (l <= r) {
int mid = l + r >> 1;
int k = 0;
for (int l = 0; l <= n; l += x) {
k += prefix[std::min(n, l + mid)];
if (l > 0) {
k -= prefix[l - 1];
}
}
if (k * 2 > n) {
r = mid - 1;
ans = mid;
}
else {
l = mid + 1;
}
}
res[x] = ans;
}
while (q--) {
int x;
cin >> x;
std::cout << res[x] << " ";
}
std::cout << "\n";
}
signed main() {
ios::sync_with_stdio(0);
std::cin.tie(0);
std::cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
solve();
}
}