「杂题乱刷」CF1904B
题目链接
题意简述
给你一个由 \(n\) 个正整数组成的序列 \(a\) 和一个分数。如果你的分数大于或等于 \(a_i\),那么你可以将分数增加 \(a_i\),并从序列中删除 \(a_i\),你需要求出对于每一个 \(a_i\) 为你的分数时你可以从这个序列中删除数的最大数量。
解题思路
我们可以考虑将询问离线并将数字从小到大排序,然后维护一个指针 \(l\),代表当前数字能到达的数,因为这样维护的话我们会发现,当一个数字比另一个数字大时,那么它所能到达的数字是不可能比比它小的数字小的,因此这样贪心是正确的。
参考代码
#include<bits/stdc++.h>
using namespace std;
long long t,n,sum,l,ans[100010];
struct node{
long long x,id;
}a[100010];
bool cmp(node x,node y){
return x.x<y.x;
}
#define forl(i,a,b) for(int i=a;i<=b;i++)
#define forr(i,a,b) for(int i=a;i>=b;i--)
#define lc(x) x<<1
#define rc(x) x<<1|1
#define lowbit(x) x&-x
#define pb push_back
#define pf push_front
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define endl '\n'
#define QwQ return 0;
int main()
{
IOS;
cin>>t;
while(t--)
{
cin>>n;
bool vis[n+1]={0};
forl(i,1,n)
cin>>a[i].x,a[i].id=i;
sort(a+1,a+1+n,cmp);
sum=0,l=1;
forl(i,1,n)
{
while(l<=i)
{
if(!vis[l])
vis[l]=1,sum+=a[l].x;
l++;
}
if(sum>=a[l].x)
while(sum>=a[l].x)
{
//cout<<l<<endl;
if(!vis[l])
vis[l]=1,sum+=a[l].x;
if(sum<a[l+1].x || l>=n)
{
ans[a[i].id]=l-1;
break;
}
l++;
}
else
ans[a[i].id]=l-2;
}
forl(i,1,n)
{
if(ans[i]==n)
ans[i]--;
cout<<ans[i]<<" ";
}
cout<<endl;
}
QwQ;
}
/*
Hack:
5
1 2 3 7 10
*/