CF913 D. Too Easy Problems

题目传送门:https://codeforces.com/problemset/problem/913/D

题目大意:
给定\(n\)个题和总时限\(T\),每道题有两个参数\(a_i,t_i\)\(t_i\)表示所需时间,\(a_i\)表示总做题数不超过\(a_i\)才能拿到第\(i\)题的分数(每道题分数都为1)。即,若你能解决第\(p_1,p_2,...,p_k\)个问题,则所获得分数为\(\sum\limits_{j=1}^k[k\leqslant a_j]\)

问所能获得的最大分数?


先介绍一下简单的做法(

贪心地去选\(t_i\)最小的,即按\(t_i\)排序

记当前选中的题数目为\(k\),如果存在最小的\(a_j\)使得\(a_j<k\),则剔除\(a_j<k\)\(t_j\)最大的,直到所有\(a_i\leqslant k\)为止

……

然后介绍一下我自己想的做法

假定我们做了\(p\)题拿了\(q\)\((p>q)\),那我们必然可以剔除所做的题目中\(a_i\)最小的\(p-q\)个题目,这样我们的最终分数至少\(q\)

故令 \(p=q\) 一定不会使答案更劣,那么我们可以二分做题数\(k\),则我们可以从所有 \(a_i\geqslant k\) 的题目中,选出 \(t_i\) 最小的\(k\)个题出来,将其\(t_i\)累加与\(T\)进行判断

用主席树维护即可

/*program from Wolfycz*/
#include<map>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define Fi first
#define Se second
#define ll_inf 1e18
#define MK make_pair
#define sqr(x) ((x)*(x))
#define pii pair<int,int>
#define int_inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
	static char buf[1000000],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>inline T frd(T x){
	int f=1; char ch=gc();
	for (;ch<'0'||ch>'9';ch=gc())	if (ch=='-')    f=-1;
	for (;ch>='0'&&ch<='9';ch=gc())	x=(x<<1)+(x<<3)+ch-'0';
	return x*f;
}
template<typename T>inline T read(T x){
	int f=1; char ch=getchar();
	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')	f=-1;
	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<1)+(x<<3)+ch-'0';
	return x*f;
}
inline void print(int x){
	if (x<0)	putchar('-'),x=-x;
	if (x>9)	print(x/10);
	putchar(x%10+'0');
}
const int N=2e5,M=1e7,V_Max=1e4;
int root[N+10];
struct S1{
	int ls[M+10],rs[M+10],Cnt[M+10],tot;
	ll V[M+10];
	void Build(int &p,int l,int r){
		if (l==r)	return;
		Cnt[p=++tot]=0,V[p]=0;
		int mid=(l+r)>>1;
		Build(ls[p],l,mid);
		Build(rs[p],mid+1,r);
	}
	void Modify(int p,int &k,int l,int r,int x){
		Cnt[k=++tot]=Cnt[p]+1; V[k]=V[p]+x;
		ls[k]=ls[p],rs[k]=rs[p];
		if (l==r)	return;
		int mid=(l+r)>>1;
		if (x<=mid)	Modify(ls[p],ls[k],l,mid,x);
		if (x>mid)	Modify(rs[p],rs[k],mid+1,r,x);
	}
	ll Query(int p,int k,int l,int r,int K){
		if (!K)	return 0;
		if (l==r)	return l*K;
		int mid=(l+r)>>1;
		if (K<Cnt[ls[k]]-Cnt[ls[p]])	return Query(ls[p],ls[k],l,mid,K);
		else	return V[ls[k]]-V[ls[p]]+Query(rs[p],rs[k],mid+1,r,K-(Cnt[ls[k]]-Cnt[ls[p]]));
	}
}CT;//Chairman Tree
struct node{
	int Limit,Time,ID;
	node(int L=0,int T=0,int I=0){Limit=L,Time=T,ID=I;}
	bool operator <(const node &tis)const{return Limit<tis.Limit;}
}A[N+10];
bool cmp(node x,node y){return x.Time<y.Time;}
bool Check(int K,int n,int T){
	node temp=node(K,0,0);
	int pos=lower_bound(A+1,A+1+n,temp)-A;
	if (n-pos+1<K)	return 0;
	ll res=CT.Query(root[pos-1],root[n],1,V_Max,K);
	return res<=T;
}
int main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	int n=read(0),T=read(0);
	for (int i=1;i<=n;i++){
		int L=read(0),_T=read(0);
		A[i]=node(L,_T,i);
	}
	sort(A+1,A+1+n);
	CT.Build(root[0],1,V_Max);
	for (int i=1;i<=n;i++)	CT.Modify(root[i-1],root[i],1,V_Max,A[i].Time);
	int l=0,r=n;
	while (l<=r){
		int mid=(l+r)>>1;
		if (Check(mid,n,T))	l=mid+1;
		else	r=mid-1;
	}
	printf("%d\n%d\n",l-1,l-1);
	node temp=node(l-1,0,0);
	int pos=lower_bound(A+1,A+1+n,temp)-A;
	sort(A+pos,A+n+1,cmp);
	for (int i=pos;i<pos+l-1;i++)	printf("%d%c",A[i].ID,i==pos+l-2?'\n':' ');
	return 0;
}
posted @ 2021-07-01 20:31  Wolfycz  阅读(46)  评论(0编辑  收藏  举报