• CF280D k-Maximum Subsequence Sum


    一、题目

    点此看题

    二、解法

    想了好久这结论终于自己整出来了,开心。

    你看这题 (dp) 稳超时,而且又没有什么好的贪心方法,不妨先建出网络流模型。

    显然可以费用流,建 (n+1) 个点,相邻两个点之间连有向边,费用为 (a_i) 流量为 (1),每个点都连源汇点,然后搞个限 (k) 点流量的点,跑最大费用最大流即可。

    但是不能直接跑网络流,因为流过一条边之后相当于反向并且费用添上负号,我们可以根据这个图总结出贪心策略:选取最大的子段,然后把这个子段负号,再继续此过程 (k) 次即可

    用线段树维护即可,要维护最大子段和最小子段以及对应的区间,时间复杂度 (O(mklog n))

    #include <cstdio>
    #include <iostream>
    #include <queue>
    using namespace std;
    const int M = 100005;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m;
    struct rec
    {
        int l,r,c;
        rec(int L=0,int R=0,int C=0) : l(L) , r(R) , c(C) {}
        bool operator < (const rec &b) const
        {
            return c<b.c;
        }
        rec operator + (const rec &b) const
        {
            return rec(l,b.r,c+b.c);
        }
    };queue<rec> q;
    struct node
    {
        rec smax,smin,lmax,lmin,rmax,rmin,sum;int fl;
        node() {fl=0;}
    }s[4*M];
    node operator + (node x,node y)
    {
        node r;
        r.smax=max(x.smax,y.smax);
        r.smax=max(r.smax,x.rmax+y.lmax);
        r.smin=min(x.smin,y.smin);
        r.smin=min(r.smin,x.rmin+y.lmin);
        r.lmax=max(x.lmax,x.sum+y.lmax);
        r.rmax=max(y.rmax,x.rmax+y.sum);
        r.lmin=min(x.lmin,x.sum+y.lmin);
        r.rmin=min(y.rmin,x.rmin+y.sum);
        r.sum=x.sum+y.sum;
        return r;
    }
    void rev(int i)
    {
        swap(s[i].smax,s[i].smin);
        swap(s[i].lmax,s[i].lmin);
        swap(s[i].rmax,s[i].rmin);
        s[i].smax.c*=-1;s[i].smin.c*=-1;
        s[i].lmax.c*=-1;s[i].lmin.c*=-1;
        s[i].rmax.c*=-1;s[i].rmin.c*=-1;
        s[i].sum.c*=-1;s[i].fl^=1;
    }
    void down(int i)
    {
        if(!s[i].fl) return ;
        rev(i<<1);rev(i<<1|1);
        s[i].fl=0; 
    }
    void add(int i,int l,int r,int id,int v)
    {
        if(l==r)
        {
            s[i].smax=s[i].smin=s[i].lmax=s[i].sum=
            s[i].lmin=s[i].rmax=s[i].rmin=rec(l,l,v);
            return ;
        }
        int mid=(l+r)>>1;down(i);
        if(mid>=id) add(i<<1,l,mid,id,v);
        else add(i<<1|1,mid+1,r,id,v);
        s[i]=s[i<<1]+s[i<<1|1];
    }
    void upd(int i,int l,int r,int L,int R)
    {
        if(L>r || l>R) return ;
        if(L<=l && r<=R)
        {
            rev(i);
            return ;
        }
        int mid=(l+r)>>1;down(i);
        upd(i<<1,l,mid,L,R);
        upd(i<<1|1,mid+1,r,L,R);
        s[i]=s[i<<1]+s[i<<1|1];
    }
    node ask(int i,int l,int r,int L,int R)
    {
        if(L<=l && r<=R) return s[i];
        int mid=(l+r)>>1;down(i);
        if(R<=mid) return ask(i<<1,l,mid,L,R);
        if(L>mid) return ask(i<<1|1,mid+1,r,L,R);
        return ask(i<<1,l,mid,L,R)+ask(i<<1|1,mid+1,r,L,R);
    }
    signed main()
    {
        n=read();
        for(int i=1;i<=n;i++)
            add(1,1,n,i,read());
        m=read();
        while(m--)
        {
            int op=read(),l=read(),r=read();
            if(op==0)
            {
            	add(1,1,n,l,r);
            	continue;
    		}
    		int k=read(),ans=0;
            while(k--)
            {
                rec t=ask(1,1,n,l,r).smax;
                if(t.c<=0) break;
                ans+=t.c;
                upd(1,1,n,t.l,t.r);
                q.push(t);
            }
            printf("%d
    ",ans);
            while(!q.empty())
            {
                rec t=q.front();q.pop();
                upd(1,1,n,t.l,t.r);
            }
        }
    }
    
  • 相关阅读:
    2018 桂林ccpc现场赛 总结
    2018 南京icpc现场赛总结
    nowcoder 203J Graph Coloring I(dfs)
    nowcoder 203A Knight(贪心+打表)
    nowcoder 202H-卡牌游戏
    nowcoder 202F-平衡二叉树
    topcoder srm 738 div1 FindThePerfectTriangle(枚举)
    codeforces 1041 E.Vasya and Good Sequences(暴力?)
    hdu 3507 Print Article(dp+斜率优化)
    hdu 1007 Quoit Design(分治)
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/14872686.html
Copyright © 2020-2023  润新知