【AtCoder arc072_f/集训队作业】 Dam

【AtCoder arc072_f/集训队作业】Dam

所以说思维还是很重要的啊

题意

<script type="math/tex" id="MathJax-Element-34">\quad</script>你有一个初始为空的水坝,每日都会有温度为 ti <script type="math/tex" id="MathJax-Element-35">t_i</script>,体积为 vi <script type="math/tex" id="MathJax-Element-36">v_i</script>的水流入。为使总水量不超过常数 L <script type="math/tex" id="MathJax-Element-37">L</script>,你每晚都可以放走一些水,使明日早晨的水可以全部流入。若水的温度不会随时间变化,只会受新流入的水影响,输出 1n <script type="math/tex" id="MathJax-Element-38">1\sim n</script>日中午在水坝是满的的条件下温度的最大值。满足第一天水坝一定会满。

分析

<script type="math/tex" id="MathJax-Element-6">\quad</script>我曾尝试往构造单调队列上想,最后在单调队列上二分答案,但这样在遇到某日温度骤减的情况时难以处理。在观摩了别人的代码后,才意识到这题根本没有那么复杂。
<script type="math/tex" id="MathJax-Element-7">\quad</script>我们断言能把前 i <script type="math/tex" id="MathJax-Element-8">i</script>天的注水在最优策略下等价变换为 i <script type="math/tex" id="MathJax-Element-9">i'</script>天的注水(表现为单调队列),同时满足:
1. <script type="math/tex" id="MathJax-Element-10">1.\;</script>这些天的总注水量为 L <script type="math/tex" id="MathJax-Element-11">L</script>。
2. <script type="math/tex" id="MathJax-Element-12">2.\;</script>被注入的水的温度随日期递增。
<script type="math/tex" id="MathJax-Element-13">\quad</script>我们归纳证明:
1. <script type="math/tex" id="MathJax-Element-14">1.\;</script>第一日显然可以
2. <script type="math/tex" id="MathJax-Element-15">2.\;</script>我们要在i-1’天中选择若干天放水。因为 t <script type="math/tex" id="MathJax-Element-16">t</script>最大的同时 tv <script type="math/tex" id="MathJax-Element-17">tv</script>也达到最大,而放水的 v <script type="math/tex" id="MathJax-Element-18">v</script>是确定的,所以放水时 t <script type="math/tex" id="MathJax-Element-19">t</script>要尽量小,故尽早放水即可(表现为队列 pop_front <script type="math/tex" id="MathJax-Element-20">pop\_front</script>),此时变为 i1′′ <script type="math/tex" id="MathJax-Element-21">i-1''</script>天的注水。
<script type="math/tex" id="MathJax-Element-22">\quad</script>再维护单调性:若第 i <script type="math/tex" id="MathJax-Element-23">i</script>日注水水温不为当前最大,由贪心可知,第 i1′′ <script type="math/tex" id="MathJax-Element-24">i-1''</script>天不放水一定不比放水劣,意味着我们可以将第 i1′′ <script type="math/tex" id="MathJax-Element-25">i-1''</script>天的注水和第 i <script type="math/tex" id="MathJax-Element-26">i</script>天的注水合并(表现为 pop_back <script type="math/tex" id="MathJax-Element-27">pop\_back</script>),重复该过程直到第 i <script type="math/tex" id="MathJax-Element-28">i'</script>日注水水温为当前最大,则 i <script type="math/tex" id="MathJax-Element-29">i'</script>天的注水构造完成( push_back <script type="math/tex" id="MathJax-Element-30">push\_back</script>)。
<script type="math/tex" id="MathJax-Element-31">\quad</script>根据最优性,将 i <script type="math/tex" id="MathJax-Element-32">i'</script>日的注水混合后的温度即为第 i <script type="math/tex" id="MathJax-Element-33">i</script>日的答案。

AC代码

#include<cstdio>
#include<algorithm>
using namespace std;
#define re_ return
#define in_ inline
#define op_ operator
#define inc(l, i, r) for(i=l; i<r; ++i)
typedef long long ll;
typedef double db;

struct wat
{
    db t; int v;
    wat(): t(0), v(0){}
    wat(db a, int b): t(a), v(b){}
    in_ wat op_+ (wat a)
    {re_ v+a.v? wat((t*v+a.t*a.v)/(v+a.v), v+a.v): wat();}
    in_ wat& op_+= (wat a)
    {re_ *this=*this+a;}
    in_ wat op_- (wat a)
    {re_ v^a.v? wat((t*v-a.t*a.v)/(v-a.v), v-a.v): wat();}
    in_ wat& op_-= (wat a)
    {re_ *this=*this-a;}
    in_ void wr(char* a)
    {printf("(%.6lf, %d)%s", t, v, a);}
};

const int mxn=1<<19;

int n, v0; wat q[mxn];

int main()
{
    int s, t; wat a, b;//b维护水坝中的所有水
//    a.wr("\n");
    scanf("%d%d", &n, &v0);
    for(s=t=0; n--;)
    {
        scanf("%lf%d", &a.t, &a.v);
        for(b+=a; b.v>v0;)//放水
            if(q[s].v<=b.v-v0) b-=q[s++];
            else q[s].v-=b.v-v0, b-=wat(q[s].t, b.v-v0);
        printf("%lf\n", b.t);
        for(;s<t && q[t-1].t>=a.t; a+=q[--t]);//合并所注水
        q[t++]=a;
    }
    re_ 0;
}
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页