Codeforces 589G Hiring(BIT + 二分)

本文解析了2015-2016年ACM-ICPC东北欧区域赛南部子区域赛G题“Hiring”的解题思路与代码实现。介绍了通过排序与树状数组维护的方法,来解决应聘者如何安排工作时间的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2015-2016 ACM-ICPC, NEERC, Southern Subregional Contest G.Hiring

题意:

一家公司对 n 个应聘者做能力评估,要求他们在最多 m 天内完成指定工作,第 j 天可以使用办公室的时间为 tj 小时。
每一个应聘者都有对应的工作要求,第 i 个应聘者每天要花 di 小时用于工作前准备,总工作量为 ri 小时(不包括准备时间)。
准备工作与完成工作都需要在办公室内进行,如果当天办公室可使用时间小于准备时间,将无法开始工作。
求每一个应聘者最早能在第几天完成工作。

思路:

先对办公室可使用时间进行升序排序,再依据准备时间对每一个应聘者进行升序排序。
用两个树状数组维护对于每一个应聘者的办公室第i天之前(包括第i天)的可工作天数,与办公室可工作时间,可工作的定义为可使用时间不小于准备时间。
若第i天之前的可工作天数*准备时间( di ) + 总工作量( ri ) <= 第i天之前的可工作时间,那么第i天即可完成所有工作。
然后二分答案,求出最小i即可。

代码:

BIT可做题一般线段树也可做,但这题BIT相对好写一些。
另外分块算法也可以水过。

//2015/10/18 23:03:07
//#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<functional>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<stack>
#include<bitset>
#include<ctime>
using namespace std;
#define clr( x , y ) memset(x,y,sizeof(x))
#define cls( x ) memset(x,0,sizeof(x))
#define pr( x ) cout << #x << " = " << x << endl 
#define pri( x ) cout << #x << " = " << x << " " 
#define test( t ) int t ; cin >> t ; int kase = 1 ; while( t-- )
#define out( kase ) printf( "Case %d: " , kase++ )
#define sqr( x ) ( x * x )
#define lowbit( x ) ( x & -x )
#define mp make_pair
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
typedef long long lint;
typedef unsigned long long ULL;
const double eps = 1e-8 ;
const int inf = 0x3f3f3f3f ;
const long long INF = 0x3f3f3f3f3f3f3f3fLL ;

const int maxn = 2 * 1e5 + 5 ;
struct C{
   int d , r , id ; 
   bool operator < ( const C &a )const {
       return d < a.d ;
   }
}c[maxn] ;

struct Day{
    int t , id ;
    bool operator < ( const Day &a ) const {
        return t < a.t ;
    }
}day[maxn] ;
int n , m , ans[maxn] ;
lint sum[maxn<<2] , cnt[maxn<<2] ;
lint query( lint C[] , int x )
{
    lint res = 0 ;
    while ( x ) {
        res += C[x] ;
        x -= lowbit( x ) ;
    }
    return res ;
}

void add( lint C[] , int x , int d )
{
    while ( x <= m ) {
         C[x] += d ;
         x += lowbit( x ) ;
    }
}
bool check( int x , int i )
{
    lint tmp1 = query( sum , x ) ;
    lint tmp2 = query( cnt , x ) ;
    if ( tmp2 * c[i].d + c[i].r <= tmp1 ) return true ;
    return false ;
}
int main()
{
    while ( cin >> n >> m ) {
        cls( cnt ) ; cls( sum ) ;
        for ( int i = 1 ; i <= m ; i++ ) scanf( "%d" , &day[i].t ) , day[i].id = i ;
        for ( int i = 1 ; i <= n ; i++ ) scanf( "%d%d" , &c[i].d , &c[i].r ) , c[i].id = i ;
        sort( day + 1 , day + m + 1 ) ;
        sort( c + 1 , c + n + 1 ) ;
        int j = m ;
        for ( int i = n ; i >= 1 ; i-- ) {
            while ( j && day[j].t >= c[i].d ) {
                add( sum , day[j].id , day[j].t ) ;
                add( cnt , day[j].id , 1 ) ;
                j-- ;
            }
            int L = 1 , R = m + 1 ;
            while ( L < R ) {
                int mid = ( L + R ) >> 1 ;
                if ( check( mid , i ) )
                    R = mid ;
                else
                    L = mid + 1 ;
            }
            if ( L == m + 1 ) 
                ans[c[i].id] = 0 ;
            else
                ans[c[i].id] = L ;
        }
        for ( int i = 1 ; i <= n ; i++ ) {
            if ( i > 1 ) printf( " " ) ;
            printf( "%d" , ans[i] ) ;
        }
        puts( "" ) ;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值