codeforces589G - Hiring(好题)

题意:

一天可以工作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;
}


你可能感兴趣的:(codeforces589G - Hiring(好题))