zoukankan      html  css  js  c++  java
  • BZOJ 1221: [HNOI2001] 软件开发

    1221: [HNOI2001] 软件开发

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 1459  Solved: 809
    [Submit][Status][Discuss]

    Description

    某软件公司正在规划一项n天的软件开发计划,根据开发计划第i天需要ni个软件开发人员,为了提高软件开发人员的效率,公司给软件人员提供了很多的服务,其中一项服务就是要为每个开发人员每天提供一块消毒毛巾,这种消毒毛巾使用一天后必须再做消毒处理后才能使用。消毒方式有两种,A种方式的消毒需要a天时间,B种方式的消毒需要b天(b>a),A种消毒方式的费用为每块毛巾fA, B种消毒方式的费用为每块毛巾fB,而买一块新毛巾的费用为f(新毛巾是已消毒的,当天可以使用);而且f>fA>fB。公司经理正在规划在这n天中,每天买多少块新毛巾、每天送多少块毛巾进行A种消毒和每天送多少块毛巾进行B种消毒。当然,公司经理希望费用最低。你的任务就是:为该软件公司计划每天买多少块毛巾、每天多少块毛巾进行A种消毒和多少毛巾进行B种消毒,使公司在这项n天的软件开发中,提供毛巾服务的总费用最低。

    Input

    第1行为n,a,b,f,fA,fB. 第2行为n1,n2,……,nn. (注:1≤f,fA,fB≤60,1≤n≤1000)

    Output

    最少费用

    Sample Input

    4 1 2 3 2 1
    8 2 1 6

    Sample Output

    38

    HINT

    Source

    分析:

    感谢机智的叶子童鞋...

    这题一开始就是用费用流写的...后来叶子说可以用三分+贪心过掉...跑的飞起...(然而我并没有用堆优化...)

    第一次写三分...

    以下来自叶子...

    显然费用与买的毛巾数成单峰函数(如果不够用函数值就是+INF)......并且无论什么时候买毛巾都和第一天买是等价的......
    所以可以三分第一天买的毛巾数,贪心求函数值,具体的贪心策略就是能用买的新毛巾就用,不能用就从第一天往后找用完没洗的慢洗,慢洗完了不够用就从昨天往前快洗.....正确性很显然是吧......

    代码:

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdio>
     5 //by NeighThorn
     6 #define inf 0x3f3f3f3f
     7 using namespace std;
     8 //眉眼如初,岁月如故
     9  
    10 const int maxn=1000+5;
    11  
    12 int n,a,b,f,fa,fb,sum,s[maxn],re[maxn],num[maxn];
    13  
    14 inline int calc(int x){
    15     int ans=x*f;
    16     memcpy(s,num,sizeof(s));
    17     memset(re,0,sizeof(re));
    18     for(int i=1;i<=n;i++){
    19         if(x){
    20             int lala=min(x,s[i]);
    21             x-=lala,s[i]-=lala,re[i]+=lala;
    22         }
    23         for(int j=1;j<=i-b-1&&s[i];j++){
    24             int lala=min(re[j],s[i]);
    25             re[j]-=lala,s[i]-=lala,ans+=fb*lala,re[i]+=lala;
    26         }
    27         for(int j=i-a-1;j>=1&&s[i];j--){
    28             int lala=min(re[j],s[i]);
    29             re[j]-=lala,s[i]-=lala,ans+=fa*lala,re[i]+=lala;
    30         }
    31         if(s[i])
    32             return inf;
    33     }
    34     return ans;
    35 }
    36  
    37 signed main(void){
    38     scanf("%d%d%d%d%d%d",&n,&a,&b,&f,&fa,&fb);sum=0;
    39     for(int i=1;i<=n;i++)
    40         scanf("%d",&num[i]),sum+=num[i];
    41     int l=1,r=sum;
    42     while(l<r-1){
    43         int mid=(l+r)>>1,Mid=(mid+r)>>1;
    44         if(calc(mid)<calc(Mid))
    45             r=Mid;
    46         else
    47             l=mid;
    48     }
    49     printf("%d
    ",min(calc(l),calc(r)));
    50     return 0;   
    51 }//Cap ou pas cap. Pas cap.
    52 

    By NeighThorn

  • 相关阅读:
    Java实现 LeetCode 242 有效的字母异位词
    Java实现 LeetCode 212 单词搜索 II
    Java实现 LeetCode 212 单词搜索 II
    Java实现 LeetCode 212 单词搜索 II
    Java实现 LeetCode 212 单词搜索 II
    Java实现 LeetCode 344 反转字符串
    Java实现 洛谷 P1208 [USACO1.3]混合牛奶 Mixing Milk
    Java实现 洛谷 P1208 [USACO1.3]混合牛奶 Mixing Milk
    Java实现 洛谷 P1208 [USACO1.3]混合牛奶 Mixing Milk
    Java实现 洛谷 P1208 [USACO1.3]混合牛奶 Mixing Milk
  • 原文地址:https://www.cnblogs.com/neighthorn/p/6266525.html
Copyright © 2011-2022 走看看