「杂题乱刷」CF1904B

题目链接

CF1904B Collecting Game

题意简述

给你一个由 \(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
*/
posted @ 2023-12-10 13:24  wangmarui  阅读(23)  评论(0编辑  收藏  举报