CF1904B 题解
题目传送门
思路
首先,显然从小到大删除数字是最优的,所以我们再准备一个将原序列
先来看接下来的朴素做法。
所有小于等于当前数的都可以直接删除,所以把
然后
接下来考虑优化
由于
然后要找到最小的
我们发现不能直接使用二分,因为不满足二段性。
但是可以将所有满足
于是问题就转化成了找到一个最小的
注意,因为有可能出现可以删除所有数的情况,所以要把
Code
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100005;
int a[N], t[N];
long long s[N];
int d[N];
void work()
{
int n;
scanf("%d", &n);
for (int i=1;i<=n;i++)
{
scanf("%d", &t[i]);
a[i] = t[i];
}
sort(a + 1, a + n + 1);
int m = 0;
for (int i=1;i<=n;i++)
{
s[i] = s[i - 1] + a[i];
if (s[i] < a[i + 1])
d[++m] = i;
}
d[++m] = n;
for (int i=1;i<=n;i++)
{
int l = 1, r = n, ans;
while (l <= r)
{
int mid = (l + r) >> 1;
if (a[mid] <= t[i])
l = mid + 1, ans = mid;
else
r = mid - 1;
}
if (ans == 1)
{
printf("0 ");
continue;
}
l = 1, r = m;
int ans2 = m;
while (l <= r)
{
int mid = (l + r) >> 1;
if (d[mid] >= ans)
r = mid - 1, ans2 = mid;
else
l = mid + 1;
}
printf("%d ", d[ans2] - 1); //减一是因为要排除自己
}
putchar('\n');
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
work();
return 0;
}