zoukankan      html  css  js  c++  java
  • 【LOJ2840】「JOISC 2018 Day 4」糖(模拟费用流)

    点此看题面

    • 给定一个长度为(n)的序列,对于所有(i=1simlceilfrac n2 ceil),求出选择(i)个不相邻元素的最大和。
    • (nle2 imes10^5)

    模拟费用流

    考虑从小到大枚举枚举选择元素个数,发现其实只有两种增加一个元素的方式:

    • 选择一个两侧都未被选择的元素。
    • 对于一个段(0101..1010)(1)表示选择),我们将其反转,选择(1010...0101)

    这就是一个模拟费用流的过程(本质是带悔贪心)。

    可以把第二种情况当成一个大元素,权值就是所有未选中的元素和减去所有选中的元素和,和第一种情况的所有点一起扔入一个堆里。

    每次取出权值最大的元素,分别考虑与它相邻的两个元素:

    • 如果它原本就与一个选中元素相邻,就将两段合并。
    • 如果它原本不与选中元素相邻,那么只是简单地向这个方向扩展一位。

    注意,对于一个选择了(1)(n)的段,我们不能再放入堆中,因为将它取反不能增加一个元素。

    代码:(O(n))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 200000
    #define LL long long
    using namespace std;
    int n,g[N+5],L[N+5],R[N+5];LL V[N+5];struct Data
    {
    	int p;LL v;I Data(CI x=0,Con LL& y=0):p(x),v(y){}
    	I bool operator < (Con Data& o) Con {return v^o.v?v<o.v:p<o.p;}//按权值排序
    };set<Data> S;
    namespace FastIO
    {
    	#define FS 100000
    	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
    	#define pc(c) (FC==FE&&(clear(),0),*FC++=c)
    	int OT;char oc,FI[FS],FO[FS],OS[30],*FA=FI,*FB=FI,*FC=FO,*FE=FO+FS;
    	I void clear() {fwrite(FO,1,FC-FO,stdout),FC=FO;}
    	Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
    	Tp I void writeln(Ty x) {W(OS[++OT]=x%10+48,x/=10);W(OT) pc(OS[OT--]);pc('
    ');}
    }using namespace FastIO;
    int main()
    {
    	RI i,j,l,r,x,y;for(read(n),i=1;i<=n;++i) read(V[i]),L[i]=R[i]=i,S.insert(Data(i,V[i]));//初始每个位置都属于第一种情况
    	LL t=0;Data k;for(i=1;i<=(n+1>>1);++i)
    	{
    		S.erase(k=*--S.end()),writeln(t+=k.v),r=R[l=k.p],g[l]=1;
    		if(l==1) V[x=1]*=-1;else if(g[l-1]) x=L[l-1],S.erase(Data(x,V[x])),V[x]-=V[l];//在左边界;两段合并
    		else x=l-1,S.erase(Data(l-1,V[l-1])),V[l-1]-=V[l],g[l-1]=1;//简单扩展一位
    		if(r==n) y=n;else if(g[r+1]) y=R[r+1],S.erase(Data(r+1,V[r+1])),V[x]+=V[r+1];//在右边界;两段合并
    		else y=r+1,S.erase(Data(r+1,V[r+1])),V[x]+=V[r+1],g[r+1]=1;//简单扩展一位
    		if(R[L[y]=x]=y,(x^1||(x-l)&1)&&(y^n||(y-r)&1)) S.insert(Data(x,V[x]));//更新左右端点关系,没有选择1或n时才加入堆
    	}return clear(),0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    机器学习实战1:朴素贝叶斯模型:文本分类+垃圾邮件分类
    Hadoop实战1:MapR在ubuntu集群中的安装
    建站、开发工具,持续更新。。。
    Mysql多表联合更新、删除
    List的深度copy和浅度拷贝
    HashMap和List遍历方法总结及如何遍历删除元素
    for循环的两种写法哪个快
    MySQL的隐式类型转换整理总结
    Java BigDecimal类的使用和注意事项
    MySQL DECIMAL数据类型
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/LOJ2840.html
Copyright © 2011-2022 走看看