CF913 D. Too Easy Problems
阿新 • • 發佈:2021-07-01
題目傳送門: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\)
……
然後介紹一下我自己想的做法
假定我們做了\(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; }