H. Sakurako's Test
原题
本题通过前缀和和二分可以解决, 原理并不是很困难, 但是比较难想到
我们只需要对每一个 x, 二分求出中位数, 预处理好即可, 二分的检查通过求k倍的x可以在调和级数的时间内实现
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 200010;
int n, m, k, q, ans, x;
void solve()
{
cin >> n >> m;
vector<int> a(n);
vector<int> c(n + 1, 0ll);
for (int i = 0; i < n; i ++ )
{
cin >> a[i];
// 记录每个数出现几次
c[a[i]] ++;
}
for (int i = 1; i <= n; i ++ )
{
// 做前缀和
c[i] += c[i - 1];
}
int res[n + 1] = {0};
for (int x = 1; x <= n; x ++ )
{
int l = 0, r = x;
while (l < r)
{
int mid = (l + r) / 2;
int cnt = c[mid];
// 调和级数, x 越大此处用时越小
for (int k = 1; k * x <= n; k ++ )
{
cnt += c[min(k * x + mid, n)] - c[k * x - 1];
}
if (cnt - 1 >= n / 2)
{
r = mid;
}
else
{
l = mid + 1;
}
}
res[x] = l;
}
while (m -- )
{
int x;
cin >> x;
cout << res[x] << " ";
}
cout << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T = 1;
cin >> T;
while (T -- )
{
solve();
}
}