hdu 3738 The Sweat Shop 单调栈加贪心思想

本文介绍了一种解决工人调度问题的算法,旨在通过合理的人员增减来最小化招聘、解雇及工资支出的成本。该算法利用单调不增栈优化求解过程,确保了在满足每日用工需求的同时,实现了总成本的最小化。

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

The Sweat Shop

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 90    Accepted Submission(s): 28


Problem Description
Many people spend thier lives in sweat shop in China. The boss of one of the famous sweat shop, GXX, is considering about the employment plan of her company.
He already knows that in the next N days, how many worker are needed for this day's work, a[i]. In additional, he will spend x yuan on recruit a worker, y yuan on fire a worker. If a worker spend a day on work in his company, GXX must pay z yuan for the wages per day.
GXX has no work before the first day and he decide to fire all the workers after these N days. Now comes to the question, how much he will pay on the employment plan in minimum.
 

Input
The first line contains only one integer T, denoting the number of test cases.
For each test cases, the first line contains only one integer N, denoting the number of days. (1 <= N <= 100000)
The next line contains three integers, x, y and z, denoting the amount of spend on recruit, fire a worker, and the daily salary of a worker. (1 <= x,y,z <= 100000)
The third line contains N integers, a[i], denoting the minimum number of workers needed for the i-th day. (1 <= a[i] <= 100000)
 

Output
For each test cases, output a single number denoting the minimum amount GXX should spend on employment plan.
 

Sample Input
1 3 10 10 1 2 1 2
 

Sample Output
46
 

题意:需要一些工人来做n天工作,每一天需要的工人数量告诉了,招聘一个工人需要x元,开除一个工人需要y元,工人每天的工资是z元,n天工作做完后,需要开除所有的工人,问怎么安排才能使得所需的总费用最少。

思路: 单调不增栈中存的是满足i-1天的可能人数,相当于一个优化。第i天时,只用遍历栈中比a[i]小的和第一个比a[i]大的即可,不需要雇佣更多的人。


#include <iostream>
#include <stdio.h>
#include <string>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
typedef __int64 ll;

using namespace std;

ll a[100009];
ll q[100009];
ll dp[100009];

int main()
{
    int T,n;
    ll x,y,z;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        scanf("%I64d%I64d%I64d",&x,&y,&z);

        for(int i=1;i<=n;i++)
            scanf("%I64d",&a[i]);

        int t=0;
        q[t]=0;
        a[0]=0;
        dp[0]=0;

        for(int i=1;i<=n;i++)
        {
            dp[i]=1ll<<60;
            while(t>=0 && a[i]>a[q[t]])
            {
                ll tmp=dp[q[t]]+a[q[t]]*z*(i-q[t]);
                tmp+=(a[i]-a[q[t]])*(x+z);
                dp[i]=min(dp[i],tmp);
                t--;
            }

            if(t>=0)//处理第一个比当前大的情况
            {
                ll tmp=dp[q[t]]+(a[q[t]]-a[i])*y+a[i]*(i-q[t])*z;
                dp[i]=min(dp[i],tmp);
            }
            q[++t]=i;
        }

        dp[n]+=a[n]*y;

        printf("%I64d\n",dp[n]);
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值