• 种树 (堆模拟网络流)


    种树

    题目描述

    cyrcyr今天在种树,他在一条直线上挖了n个坑。这n个坑都可以种树,但为了保证每一棵树都有充足的养料,cyrcyr不会在相邻的两个坑中种树。而且由于cyrcyr的树种不够,他至多会种k棵树。假设cyrcyr有某种神能力,能预知自己在某个坑种树的获利会是多少(可能为负),请你帮助他计算出他的最大获利。

    输入输出格式

    输入格式:

    第一行,两个正整数n,k。

    第二行,n个正整数,第i个数表示在直线上从左往右数第i个坑种树的获利。

    输出格式:

    输出1个数,表示cyrcyr种树的最大获利。

    输入输出样例

    输入样例#1: 复制

    6 3
    100 1 -1 100 1 -1

    输出样例#1: 复制

    200

    说明

    对于20%的数据,n<=20。

    对于50%的数据,n<=6000。

    对于100%的数据,n<=500000,k<=n/2,在一个地方种树获利的绝对值在1000000以内。

    题解

    一道非常好的堆模拟网络流题。
    首先我们来想想(O(n^2))
    很显然的两重循环dp
    第一重枚举第i个位置,第二重枚举选了j颗树。
    对于O(n)的模拟。
    我们首先明确选了 i 就不能选 i-1 和 i+1。
    所以所有的情况都是由选 i 和选 i-1 ,i+1 产生的。
    选 i 时, i 的贡献应当是大于 i-1 和 i+1 的。
    但是当我们发现选 i-1 和 i+1 要更好时呢?
    网络流有一个操作就是反悔。
    我们是不是也可以反悔一下呢?
    因为先选了 i ,那么下一次选择的时候,如果反悔就是选两边
    就是选了周围两个点,不反悔就是选其他点
    那么把周围两个点维护为一个点就可以了。
    (vi[i]=vi[l[i]]+vi[r[i]]-vi[i])
    然后维护一下 (l)(r) 数组。

    代码

    #include<cstdio>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    using namespace std;
    priority_queue<pair<int,int> >q;
    int vis[1000001],ch[1000001],n,m;
    long long ans;
    struct node{
        int vi,id,l,r;
    }t[1000001];
    int read(){
        int x=0,w=1;char ch=getchar();
        while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*w;
    }
    
    int main(){
        n=read();m=read();
        for(int i=1;i<=n;i++){
            ch[i]=t[i].vi=read();t[i].id=i;
            t[i].l=i-1;t[i].r=i+1;
            q.push(make_pair(ch[i],i));
        }
        t[0].r=1;t[n+1].l=n;
        while(m&&!q.empty()){
            while(vis[q.top().second])q.pop();
            int x=q.top().second;q.pop();
            if(t[x].vi<0)break;
            ans+=t[x].vi;
            t[x].vi=t[t[x].l].vi+t[t[x].r].vi-t[x].vi;
            vis[t[x].l]=vis[t[x].r]=1;
            t[x].l=t[t[x].l].l;t[t[x].l].r=x;
            t[x].r=t[t[x].r].r;t[t[x].r].l=x;
            q.push(make_pair(t[x].vi,x));
            m--;
        }
        printf("%lld",ans);
        return 0;
    }
    
  • 相关阅读:
    windows版redis
    苹果Mac电脑文件夹路径怎么看?“访达”也能显示文件路径
    Windows下Nginx初始化
    Win10微信查看图片卡顿或发送图片卡顿的原因和解决方法
    【Windows安装RabbitMQ详细教程】
    pb中打印设置
    字典pop,filter
    case when 用法
    自定义函数封装变量
    MySQL WorkBench 导入数据
  • 原文地址:https://www.cnblogs.com/hhh1109/p/9571549.html
Copyright © 2020-2023  润新知