2015湖南省队集训DAY8——梦工厂

梦工厂 (yume.cpp/c/pas)

Time Limit: 1 s Memory Limit: 128 M

问题描述

「有时候用烂了的名字也会别有深意」
——摘自EN 语录
“这里是制造快乐,编织幸福的梦工厂!才不是你们想的什么奇怪的工厂呢!哼!”
这是你来到这个奇妙的地方所听到的第一句话,竟然还是一头身长三米的狗熊发出来的。
一开始看到梦工厂这块牌匾时,你心里想的是什么呢?如果真的是洋溢着青涩而纯洁的
梦想,那就太棒了!
初来乍到,狗熊先生决定给你先大致地讲解一下工厂的运作过程。
“要知道,我们这里可是梦工厂,为小孩子们生产快乐与幸福的梦工厂!”,狗熊先生
不断地重复着梦工厂的定义。尽管脑袋晕晕乎乎的,但是你最终还是知道了,这个工厂是专
门生产快乐与幸福这样的情绪的,用来送给那些闷闷不乐或者是受到了挫折的小孩子,让他
们重展笑颜。
“但是,我们遇到了一个问题…”,狗熊先生的语气低沉了下来。
“最近不开心的小孩子越来越多了,我们需要生产的快乐也越来越多了,但是我们的生
产线是由n道工序构成,每个单位时间里每道工序最多只能容纳一个快乐。当一个快乐被
一个工序加工完后,会立刻传到下一道工序。”
“然后呢,怎么了,这不挺好的吗?”,你好奇道。
“好什么呀!快乐会被强制传到下一道工序,如果下一道工序里也有一个快乐的话,那
就会爆炸!爆炸懂吗!瞬间爆炸!”,狗熊先生语气高昂了起来。
“之前我们为了防止爆炸,都是等一个快乐所有工序生产好之后才开始生产另一个快乐
的。但是我想了几百年,觉得可以早点开始生产的,只要保证它们不会在同一时刻出现在同
一道工序上就行了。”,狗熊先生骄傲地挺起胸膛,有点可怕。
“顺便告诉你吧!每道工序有个复杂指数 Ti ,一个快乐有个快乐指数 Fj ,第 j 个快乐在
i道工序中要消耗的时间是 FjTi ,而且快乐必须按顺序生产。”
“既然我什么都告诉你了,嘿嘿”,狗熊先生露出了狰狞的笑容,食肉的
“你就帮我安排一下怎么生产最好吧,告诉我最短的全部生产完的时间就
哦,不然就拿你打牙祭!”
这是梦工厂吗?是梦吧?

输入格式

第一行两个整数 n m表示工序道数、需生产的快乐个数。
第二行 n 个整数,分别表示复杂指数Ti
第三行 m 个整数,分别表示快乐指数Fi

输出格式

一个正整数为最短时间。
Sample Input
3 3
2
1
1
2
1
1
Sample Output
11

题解与吐槽

南雅的这题面。。。说人话好不

花了快2个小时写这题暴力,又两个小时调一个傻逼凸包。
感觉终于有点明白斜率优化是啥东西了。

我们先把 Ti 的前缀和求出来,记做 sumi ,然后维护把前 i1 个物品全部处理完的时间。然后对于第 i 件物品,我们要使它无论如何不能与前一个同时出现在一个阶段,所以我们可以求出sumjfi1sumj1fi的最大值,并以这个值减去节省下来的时间。

上面那个是暴力,然后我们发现可以把那个式子转化一下,就变成了经典的斜率优化问题。我们维护 (sumi1,sumi) 形成的上凸包,然后每次询问时二分查找即可。

下面上代码

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef double db;

const int inf=0x3f3f3f3f;

int getint()
{
    char c=getchar();
    int f=1,g=0;
    while(c>'9' || c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c<='9' && c>='0')g=(g<<3)+(g<<1)+c-'0',c=getchar();
    return f*g;
}

const int maxn=2000005;

int top;
int sum[maxn];
int f[maxn];
int t[maxn];
int n,m;

db slp[maxn];
ll ans;
int q[maxn];

db slope(int j,int k)
{
    db temp1=(db)sum[j-1]-(db)sum[k-1];
    db temp2=(db)sum[j]-(db)sum[k];
    return temp1/temp2;
}

int findpos(db x)
{
    int l=1;
    int r=top-1;
    if(x<slp[l])return q[1];
    if(x>slp[r])return q[top];
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(slp[mid]<x)
        {
            l=mid+1;
        }
        else r=mid;
    }
    return q[l];
}

int main()
{
    freopen("yume.in","r",stdin);
    freopen("yume.out","w",stdout);

    n=getint();
    m=getint();

    for(int i=1;i<=n;i++)
    {
        t[i]=getint();
        sum[i]=sum[i-1]+t[i];
    }

    for(int i=1;i<=m;i++)
    {
        f[i]=getint();
    }

    for(int i=1;i<=n;i++)
    {
        while(top>1 && slp[top-1]>=slope(q[top],i))
        {
            top--;
        }
        q[++top]=i;
        slp[top-1]=slope(q[top],q[top-1]);
    }
    for(int i=1;i<=m;i++)
    {
        db tem=(db)f[i-1]/(db)f[i];
        int temp=findpos(tem);

        ll mx=(ll)sum[temp]*(ll)f[i-1]-(ll)sum[temp-1]*(ll)f[i];

        mx-=(ll)sum[n]*((ll)f[i-1]-(ll)f[i]);
        mx=max(0ll,mx);

        ans+=mx;
    }
    printf("%lld\n",ans);

    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值