[ 线段树 单调队列 ] Codeforces859F Ordering T-Shirts

来源:互联网 发布:网络专题排版设计 编辑:程序博客网 时间:2024/04/30 05:56

假设前 i 号衬衫买了 ti 个,容易发现答案是合法的仅当

min(c,k=2i12j1sk)tjti1, ij

Si 表示 s 的前缀和。
min(c,S2j1S2i)tjti1, ij

从左到右枚举 i 求出 ti
ti=max(min(c,S2i1S2j)+tj), j<i

cS2i1S2j ,由于 ti 是非负的,i 从最大的 j 转移。
否则,用线段树或单调队列记一下 tjS2j 的最大值再转移。

#include<bits/stdc++.h>using namespace std;#define ll long longinline char nc(){    static char buf[100000],*p1=buf,*p2=buf;    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}inline void Read(int& x){    char c=nc();    for(;c<'0'||c>'9';c=nc());    for(x=0;c>='0'&&c<='9';x=(x<<3)+(x<<1)+c-48,c=nc());}inline void Read(ll& x){    char c=nc();    for(;c<'0'||c>'9';c=nc());    for(x=0;c>='0'&&c<='9';x=(x<<3)+(x<<1)+c-48,c=nc());}#define N 200010ll s[N<<1],t[N],m,Ans,c[N<<2];int i,j,k,n,x;inline void Update(int x,int l,int r,int y,ll z){    if(l==r){        c[x]=z;        return;    }    int Mid=l+r>>1;    if(y<=Mid)Update(x<<1,l,Mid,y,z);else Update(x<<1|1,Mid+1,r,y,z);    c[x]=max(c[x<<1],c[x<<1|1]);}inline ll Query(int x,int l,int r,int L,int R){    if(l>R||r<L)return -1e18;    if(l>=L&&r<=R)return c[x];    int Mid=l+r>>1;    return max(Query(x<<1,l,Mid,L,R),Query(x<<1|1,Mid+1,r,L,R));}int main(){    Read(n);Read(m);    for(i=1;i<=n*2-1;i++)Read(x),s[i]=s[i-1]+x;    for(i=1;i<=n;i++){        for(;j<i&&s[2*i-1]-s[2*j]>m;j++);        if(j>0)t[i]=t[j-1]+m;        if(j<i)t[i]=max(t[i],s[i*2-1]+Query(1,0,n,j,i-1));        Update(1,0,n,i,t[i]-s[i<<1]);    }    cout<<t[n]<<endl;    return 0;}
原创粉丝点击