题意:
一天可以工作ti时间,有n天,问一个工作者最多可以在第几天完成他的工作
一天工作之前必须先要准备xi的时间
由题意可知,要想完成这份工作,一定要在ti>xi的天数中做工作
已经知道了哪几天这个人会去工作,那么显然二分答案
所以问题便成为了求哪几天他会去工作,所以联想到用树状数组去维护,
首先先对时间升序排序,对准备时间升序排序
反向循环,当时间大于准备时间时,便把这天的准备时间加入到树状数组中,同时再利用一个树状数组,对天数+1
#include <map> #include <set> #include <stack> #include <queue> #include <cmath> #include <ctime> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; #define INF 0x3f3f3f3f #define inf -0x3f3f3f3f #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define mem0(a) memset(a,0,sizeof(a)) #define mem1(a) memset(a,-1,sizeof(a)) #define mem(a, b) memset(a, b, sizeof(a)) typedef long long ll; int n,m; const int maxn=200000+1000; int ans[maxn]; __int64 sum[maxn],cnt[maxn]; struct Day{ int id; __int64 num; friend bool operator <(Day a,Day b){ return a.num < b.num; //num小的结构体优先 } }t[maxn]; struct task{ __int64 prepare,cost; int id; friend bool operator <(task a,task b){ return a.prepare < b.prepare; //prepare小的结构体优先 } }people[maxn]; __int64 query(__int64 c[],int x){ __int64 ret=0; while(x>0){ ret+=c[x]; x-=(x&-x); } return ret; } void add(__int64 c[],int x,__int64 d){ while(x<=m){ c[x]+=d; x+=(x&-x); } } bool check(int i,int x){ __int64 tmp1=query(cnt,x),tmp2=query(sum,x); if(tmp1*people[i].prepare+people[i].cost<=tmp2) return true; return false; } int main(){ while(scanf("%d%d",&n,&m)!=EOF){ for(int i=1;i<=m;i++){ scanf("%I64d",&t[i].num); t[i].id=i; } for(int i=1;i<=n;i++){ scanf("%I64d%I64d",&people[i].prepare,&people[i].cost); people[i].id=i; } sort(t+1,t+m+1); sort(people+1,people+n+1); int j=m; for(int i=n;i>=1;i--){ while(j&&t[j].num>=people[i].prepare){ add(sum,t[j].id,t[j].num);//把能处理任务的天数加进去 add(cnt,t[j].id,1);//把i天处理的天数记录 j--; } int low=1,high=m+1; while(high-low>=0){ int mid=(high+low)/2; if(check(i,mid)) high=mid-1; else low=mid+1; } if(high!=m+1) ans[people[i].id]=low; else ans[people[i].id]=0; } printf("%d",ans[1]); for(int i=2;i<=n;i++) printf(" %d",ans[i]); printf("\n"); } return 0; }