H. Sakurako's Test
H. Sakurako's Test
Sakurako will soon take a test. The test can be described as an array of integers and a task on it:
Given an integer , Sakurako can perform the following operation any number of times:
- Choose an integer () such that ;
- Change the value of to .
Using this operation any number of times, she must find the minimum possible median of the array .
Sakurako knows the array but does not know the integer . Someone let it slip that one of the values of will be in the next test, so Sakurako is asking you what the answer is for each such .
The median of an array of length is the element that stands in the middle of the sorted array (at the -th position for even , and at the -th for odd)
Input
The first line contains one integer () — the number of test cases.
The first line of each test case contains two integers and () — the number of elements in the array and the number of queries.
The second line of each test case contains integers () — the elements of the array.
The following lines each contain one integer ().
It is guaranteed that the sum of across all test cases does not exceed . The same guarantee applies to the sum of across all test cases.
Output
For each test case, output 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
解题思路
首先要知道当集合中的元素越小,那么集合中元素的中位数越小。因此我们应该让一个数尽可能减去 ,最后得到 。对于固定的 ,在执行操作后中位数就已经确定了,即第 小的数。但由于需要对每个 模 ,直接暴力做的话时间复杂度是 。
不妨换个思虑,对于每个 二分出最小的中位数(初始时二分的左右端点分别为 和 ),假设二分点为 ,那么余数不超过 的元素个数如果至少为 ,则说明中位数小于等于 。因此现在问题是如何快速求出模 后不超过 的元素数量。
把每个元素看作是 的形式,因此满足模 不超过 的数可以表示成区间 。由于 ,因此 。枚举 ,累加值在 内的元素数量(可以用权值前缀和作差得到),最后判断累加的值是否不小于 即可。
利用调和级数的性质,我们直接预处理出 的答案。时间复杂度就是 。最后 查询即可。
AC 代码如下,时间复杂度为 :
#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
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/18393746
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.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 环形石子合并