CF280D k-Maximum Subsequence Sum

CF280D k-Maximum Subsequence Sum

线段树维护贪心

要取\(k\)次,考虑贪心策略如下

先取最大的连续子段,然后有两种决策:

? 1.从原来的某一段已经被取的连续子段中取一段最小的断开那个子段

? 2.另取一个子段

(非常有道理对吧)

接下来考虑用线段树优化这个贪心问题

其实就是每次取最大的一段,然后将这一段的正负号翻过来,以后再取时就是断开子段了

是一个简单的线段树问题

#include<bits/stdc++.h>
using namespace std;

#define reg register
typedef long long ll;
#define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i)

template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }
template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
inline int max(int a,int b){ return a>b?a:b; }

char IO;
int rd(){
    int s=0,f=0;
    while(!isdigit(IO=getchar())) f|=(IO=='-');
    do s=(s<<1)+(s<<3)+(IO^'0');
    while(isdigit(IO=getchar()));
    return f?-s:s;
}

const int N=1e5+10,INF=1e9;

int n,m,a[N];

struct Node{
    int s;
    int ls,lp,rs,rp;
    int ma,l,r; // 要维护最优子段的位置
    Node operator + (const Node x) const {
        Node res;
        res.s=s+x.s;
        if(ls>s+x.ls) res.ls=ls,res.lp=lp;
        else res.ls=x.ls+s,res.lp=x.lp;
        if(x.rs>rs+x.s) res.rs=x.rs,res.rp=x.rp;
        else res.rs=x.s+rs,res.rp=rp;
        res.ma=max(max(ma,x.ma),rs+x.ls);
        if(res.ma==ma) res.l=l,res.r=r;
        else if(res.ma==x.ma) res.l=x.l,res.r=x.r;
        else res.l=rp,res.r=x.lp;
        return res;
    }
}s1[N<<2],s2[N<<2];  // 同步处理一个正负号翻转之后的值
int t[N<<2];

void Down(int p) {
    if(!t[p]) return;
    t[p<<1]^=1;
    t[p<<1|1]^=1;
    swap(s1[p<<1],s2[p<<1]);
    swap(s1[p<<1|1],s2[p<<1|1]);
    t[p]=0;
}

void Build(int p,int l,int r) {
    if(l==r) {
        s1[p]=(Node){a[l],a[l],l,a[l],l,a[l],l,l};
        s2[p]=(Node){-a[l],-a[l],l,-a[l],l,-a[l],l,l};
        return;
    }
    int mid=(l+r)>>1;
    Build(p<<1,l,mid);
    Build(p<<1|1,mid+1,r);
    s1[p]=s1[p<<1]+s1[p<<1|1];
    s2[p]=s2[p<<1]+s2[p<<1|1];
}

void Upd(int p,int l,int r,int x,int y) {
    if(l==r) {
        s1[p]=(Node){y,y,l,y,l,y,l,l};
        s2[p]=(Node){-y,-y,l,-y,l,-y,l,l};
        return;
    }
    Down(p);
    int mid=(l+r)>>1;
    x<=mid?Upd(p<<1,l,mid,x,y):Upd(p<<1|1,mid+1,r,x,y);
    s1[p]=s1[p<<1]+s1[p<<1|1];
    s2[p]=s2[p<<1]+s2[p<<1|1];
}

void Set(int p,int l,int r,int ql,int qr) {
    if(l==ql&&r==qr) {
        t[p]^=1;
        swap(s1[p],s2[p]);
        return;
    }
    Down(p);
    int mid=(l+r)>>1;
    if(qr<=mid) Set(p<<1,l,mid,ql,qr);
    else if(ql>mid) Set(p<<1|1,mid+1,r,ql,qr);
    else Set(p<<1,l,mid,ql,mid),Set(p<<1|1,mid+1,r,mid+1,qr);
    s1[p]=s1[p<<1]+s1[p<<1|1];
    s2[p]=s2[p<<1]+s2[p<<1|1];
}

Node Que(int p,int l,int r,int ql,int qr) {
    if(l==ql&&r==qr) return s1[p];
    int mid=(l+r)>>1;
    Down(p);
    if(qr<=mid) return Que(p<<1,l,mid,ql,qr);
    else if(ql>mid) return Que(p<<1|1,mid+1,r,ql,qr);
    else return Que(p<<1,l,mid,ql,mid)+Que(p<<1|1,mid+1,r,mid+1,qr);
}

int tl[N],tr[N];

int main(){
    n=rd();
    rep(i,1,n) a[i]=rd();
    Build(1,1,n);
    rep(querys,1,m=rd()) {
        int opt=rd();
        if(!opt) {
            int x=rd(),y=rd();
            Upd(1,1,n,x,y);
        } else {
            int l=rd(),r=rd(),k=rd(),s=0,ans=0;
            rep(i,1,k) {
                Node t=Que(1,1,n,l,r);
                tl[i]=t.l,tr[i]=t.r;
                s+=t.ma;
                ans=max(ans,s);
                Set(1,1,n,tl[i],tr[i]);
            }
            rep(i,1,k) Set(1,1,n,tl[i],tr[i]);
            printf("%d\n",ans);
        }
    }
}

原文地址:https://www.cnblogs.com/chasedeath/p/11824610.html

时间: 2024-08-04 12:11:20

CF280D k-Maximum Subsequence Sum的相关文章

Maximum Subsequence Sum - 最大子列和问题_C语言实现

第一次写这方面的blog.自己也是初次接触相关知识,写的有不妥的地方十分欢迎大家指正~ 这是浙大PAT上的一道算法题(据说是浙大04年研究生复试题),题目是这样的: Maximum Subsequence Sum Given a sequence of KK integers { N_1N?1??, N_2N?2??, ..., N_KN?K?? }. A continuous subsequence is defined to be { N_iN?i??, N_{i+1}N?i+1??, ..

Maximum Subsequence Sum 最大子序列和的进击之路

本文解决最大子序列和问题,有两个题目组成,第二个题目比第一个要求多一些(其实就是要求输出子序列首尾元素). 01-复杂度1 最大子列和问题   (20分) 给定KK个整数组成的序列{ N1??, N2??, ..., NK?? },"连续子列"被定义为{ N?i??, Ni+1 ..., Nj },其中 1≤i≤j≤K."最大子列和"则被定义为所有连续子列元素的和中最大者.例如给定序列{ -2, 11, -4, 13, -5, -2 },其连续子列{ 11, -4,

pat1007. Maximum Subsequence Sum (25)

1007. Maximum Subsequence Sum (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue Given a sequence of K integers { N1, N2, ..., NK }. A continuous subsequence is defined to be { Ni, Ni+1, ..., Nj } where 1 <= i <= j <= K. The

1007. Maximum Subsequence Sum (25)——PAT (Advanced Level) Practise

题目信息: 1007. Maximum Subsequence Sum (25) 时间限制 400 ms 内存限制 32000 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue Given a sequence of K integers { N1, N2, ..., NK }. A continuous subsequence is defined to be { Ni, Ni+1, ..., Nj } where 1 <= i <= j <=

1007 Maximum Subsequence Sum (25)(25 分)

1007 Maximum Subsequence Sum (25)(25 分) Given a sequence of K integers { N~1~, N~2~, ..., N~K~ }. A continuous subsequence is defined to be { N~i~, N~i+1~, ..., N~j~ } where 1 <= i <= j <= K. The Maximum Subsequence is the continuous subsequence

1007 Maximum Subsequence Sum(25 分)

1007 Maximum Subsequence Sum(25 分) Given a sequence of K integers { N?1??, N?2??, ..., N?K?? }. A continuous subsequence is defined to be { N?i??, N?i+1??, ..., N?j?? } where 1≤i≤j≤K. The Maximum Subsequence is the continuous subsequence which has th

[PTA] PAT(A) 1007 Maximum Subsequence Sum (25 分)

目录 Problem Description Input Output Sample Sample Input Sample Output Solution Analysis Code Problem portal: 1007 Maximum Subsequence Sum (25 分) Description Given a sequence of $K$ integers { $N_{1}?$, $N_{2}?$, $...$, $N_{K}$ }. A continuous subsequ

1007 Maximum Subsequence Sum (25分) 求最大连续区间和

1007 Maximum Subsequence Sum (25分) Given a sequence of K integers { N?1??, N?2??, ..., N?K?? }. A continuous subsequence is defined to be { N?i??, N?i+1??, ..., N?j?? } where 1≤i≤j≤K. The Maximum Subsequence is the continuous subsequence which has th

Algorithm for Maximum Subsequence Sum z

MSS(Array[],N)//Where N is the number of elements in array { sum=0; //current sum max-sum=0;//Maximum Sum seq-start=0;//start of the subsequence seq-end=0;//end of the subsequence for(i=0;i<N;i++){ sum=sum+Array[i]; if(sum<0){ sum=0; seq-start++; }

dynamic programming 之Maximum Sub-Sequence Sum(最大子序列和问题)

问题描述: 给定一个整数序列, 序列中可能有负数. 目的是找出这个序列的连续子序列(即子序列的元素的选取是连续的从序列中选取的).即通过确定i, j 的值,  使得的值达到最大. 我们定义, 当所有的元素为负数值的时候, 那么maximum subsequence sum 为0. 下面我们用动态规划的技术去求解. 为了找到最大连续子序列和,  不难看出, 在扩展我们的求和窗口的时候, 当新加进窗口的元素市负数的时候, 只要我们得到的新的求和窗口的值求和不是负数, 那么我们就不能丢掉这个新的负数.