1 条题解

  • 0
    @ 2025-8-24 21:45:56

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar CYJian
    今日はこっちの地方はどしゃぶりの晴天でした,昨日もずっと暇で一日満喫してました

    搬运于2025-08-24 21:45:56,当前版本为作者最后更新于2018-04-05 15:03:58,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    震惊!一道爆搜题竟然被评成了黑题!!!

    咳咳。。。

    没错,这道题就是一道爆搜题。。。

    n <= 15,这让我们习惯性的想到了状压。。。

    然后仔细想想,如果我们已经选好了要接受哪些订单,可不可以直接判断呢??

    或者说更进一步,如果已经知道当前的生产力、剩了多少东西、接下来还有哪些订单,我们能不能求出在接下一个订单之前可以有多少时间提高生产力呢??

    (这么多废话终于说完了。。。)

    说了这么多显然是可以的嘛。。。

    我们设可以有x单位时间来提高生产力,那么如果当前离下一个订单的时间为T时,这个订单要P个产品,工厂拥有M的生产力时,显然有如下方程:

    (M+x)(Tx)=P(M + x) * (T - x) = P

    整理后就可以得到:

    x2+(MT)x+PMT=0x^2 + (M - T) * x + P - M * T = 0

    利用根的判别式算一下有没有根,如果没有就说明无法接下这个订单,否则就可以拥有

    $$\biggl \lfloor \frac{T - M + \sqrt{(M + T)^2 - 4P}}{2} \biggr \rfloor $$

    的时间来增加生产力。

    然后就这样枚举下去,每次如果方案可行就用这些订单的收入来更新答案。

    下面贴代码:

    #include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    
    const int N = 20;
    
    struct P {
        int t; //订单的时间
        int c; //需要的产品数量
        int p; //得到的报酬
    
        friend bool operator< (P a, P b) { //按照时间排好序
            return a.t < b.t;
        }
    }S[N], a[N];
    
    int n;
    int tot;
    ll res;
    // 设可以有x天提高生产力则可以列出方程: (Make + x) * (Time - x) = Need
    // 整理得: x^2 + (Make - Time) * x + Need - Make * Time = 0
    // 解方程即可
    ll js(ll Make, ll Time, ll Need) { 
        ll a = 1;
        ll b = Make - Time;
        ll c = Need - Make * Time;
        ll derta = b * b - 4 * a * c;
        if(derta < 0) return -1;
        return floor((-b + sqrt(derta)) / 2 / a);
    }
    //检查当前枚举的方案可不可行,可行就更新答案
    void solve(int Now) {
        tot = 0;
        ll num = 0;
        for(int i = 1; i <= n; i++)
            if(Now & (1 << i - 1))
                S[++tot] = a[i], num += a[i].p; //将当前状态的订单加入栈
        ll Make = 1; //生产力
        ll Have = 0; //剩余的产品数量
        for(int i = 1; i <= tot; i++) {
            ll t = S[i].t - S[i - 1].t; //在下一个订单前能够提高生产力的时间,最大就是这个
            ll sum = 0; //累加所需的产品
            for(int j = i; j <= tot; j++) {
                sum += S[j].c;
                if(sum > Have)
                    t = min(t, js(Make, S[j].t - S[i - 1].t, sum - Have)); //用算出来的时间更新当前的时间
            }
            if(t < 0) return ; //说明不可行
            Make += t; //更新生产力
            Have += Make * (S[i].t - S[i - 1].t - t) - S[i].c; //更新库存
        }
        res = max(res, num);
    }
    
    int main() {
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)
            scanf("%d%d%d", &a[i].t, &a[i].c, &a[i].p);
        sort(a + 1, a + 1 + n); //按照时间排好序
        for(int i = 0; i < (1 << n); i++)
            solve(i);
        printf("%lld\n", res);
        return 0;
    }
    
    • 1

    信息

    ID
    2234
    时间
    1000ms
    内存
    125MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者