【Kickstart】2019 Round E - Code-Eat Switcher

解法

对于每天的ab,我们不妨假设所有的时间都用来coding,这样能得到totalC的coding时间

  • 显然,如果totalC<a,这天显然不能完成
  • 否则,我们假设able = totalC-a,这表示多出来了able的coding时间,这些时间可以转化成吃饭时间
    我们肯定更prefer效率高的转化,比如我同样减少1单位的coding时间,在不同的timeslot可能会增加不同的吃饭时间
    所以我们要把slots按照 E C \frac{E}{C} CE从大到小排序,然后依次开始减,如果在able减到0之前能达到b,那么这天是可行的
    这是 O ( D S ) O(DS) O(DS)复杂度的
    现在要继续优化:
  1. 如果有很多天,a相同,但是b不同,我们只需要求出来对于同一个a,当able为0时可以获得的最大吃饭时间是maxE。在这些天里,如果b不超过maxE,那么可以做到,否则不行
  2. 当我们做完a1的转化后,得到一个maxE1,然后我们要做a2的转化,并且a2<a1。显然,在a1转化里被转化成吃饭的时间在a2转化里也需要被转化成吃饭的时间。所以我们可以对a从大到小排序,这样每次不用再从头遍历slots。

要注意的是,优化完之后,当从某个slot退出的时候,它可能并未完全转化,要处理一下这个问题

#include <stdio.h>
#include <string>
#include <iostream>
#include <memory.h>
#include <stdlib.h>
#include <cmath>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <algorithm>
#include <functional>

#define MAXD 100010
#define MAXS 100010
#define ZERO 10e-6
#define NINF -100000
#define INF 65536


using namespace std;

typedef long long lld;

class SLOT{
public:
    int c,e;
    bool operator < (const SLOT &b) const  {
        return b.c*e>c*b.e;
    }
};


int D,S;
map<int, vector<pair<int,int>>> days;
SLOT slots[MAXS];


bool isEQ(double a, double b) {
    return fabs(a-b)<=ZERO;
}

bool isLE(double a, double b) {
    return isEQ(a,b) || a<b;
}

double max(double x, double y) {
    return isLE(x,y)?y:x;
}
double min(double x, double y) {
    return isLE(y,x)?y:x;
}

string solve() {
    string ans(D,'Y');
    int totalC = 0;
    for(int i=0;i<S;++i) totalC += slots[i].c;
    double nowB = 0;
    int used = 0;
    int j = 0;
    for (auto ele = days.end(); ele!=days.begin();) {
        ele--;
        int a = ele->first;
        if (totalC<a) {
            for(auto &bb:ele->second) {
                ans[bb.second] = 'N';
            }
        } else {
            int able = totalC - a;
            for(;j<S;++j) {
                int change = min(slots[j].c-used, able);
                nowB += 1.0*change/slots[j].c*slots[j].e;
                able -= change;
                if (able==0) {
                    used += change;
                    break;
                } else used = 0;
            }
            for(auto &bb:ele->second) {
                if (bb.first>(int)nowB) ans[bb.second] = 'N';
            }
            totalC = able+a;
        }
    }
    return ans;
}

int main() {
    int t;
    scanf("%d",&t);
    for(auto round=1;round<=t;++round) {
        scanf("%d%d",&D,&S);
        for(int i=0;i<S;++i) {
            scanf("%d%d",&slots[i].c,&slots[i].e);
        }
        sort(slots,slots+S);
        days.clear();
        for(int i=0;i<D;++i) {
            int a,b;
            scanf("%d%d",&a,&b);
            if (days.find(a)==days.end()) {
                days[a] = vector<pair<int,int>>();
            }
            days[a].push_back(make_pair(b,i));
        }
        printf("Case #%d: %s\n",round, solve().c_str());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值