2017-3-12四校联考

感觉这天一整天有点头昏脑涨,晚上吃完饭就睡过去了连博客也没写

T1大判断,T3看上去比较裸的二分完线段树优化DP,就T2看上去比较有意思,没想到最后正解还要用什么积分orz。最后没交,补一道T3,其他没什么打的欲望。

T3.序列

题目大意:给定正整数m和两个长度为n的序列对(ai,bi),要求把序列分成若干段,满足:1.若i<j且i与j不在同一段,则bi>aj;2.每一段a的最大值之和不超过m。要求划分方案满足条件的同时每一段b的和的最大值最小。(n<=100000)

思路:条件1说明只有前i个b的最小值大于后n-i个a的最大值,i才能作为段的末尾,预处理一下可以把不能分段的缩成一个点(新的a取段中a最大值,b取段中b的和),这样我们之后就不用考虑条件1了。我们二分答案,DP求出每一段b之和都不超过当前二分出的答案时最小的各段a最大值之和。f[i]表示序列前i个分成若干段最小的a最大值之和,则f[i]=min(f[j]+max(a[i+1]~a[j]))(sum(b[i+1]~b[j])<=当前二分的答案),可以用线段树大力维护,总复杂度O(nlogn^2)。

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
inline ll read()
{
    ll x;char c;
    while((c=getchar())<'0'||c>'9');
    for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
    return x;
}
#define MN 100000
#define INF (1LL<<60)
#define L (x<<1)
#define R (x<<1^1)
int n,a[MN+5],ma[MN+5];
ll b[MN+5],sb[MN+5],mb[MN+5],f[MN+5];
struct node{int l,r,mx,mk;ll mf,ms;}t[MN*4+5];
inline void up(int x)
{
    t[x].mx=max(t[L].mx,t[R].mx);
    t[x].mf=min(t[L].mf,t[R].mf);
    t[x].ms=min(t[L].ms,t[R].ms);
}
inline void mark(int x,int z)
{
    t[x].mx=t[x].mk=z;
    t[x].ms=t[x].mf+z;
}
#define down(x) if(t[x].mk)mark(L,t[x].mk),mark(R,t[x].mk),t[x].mk=0
void build(int x,int l,int r)
{
    t[x].l=l;t[x].r=r;t[x].mk=0;
    if(l==r){t[x].mx=0;t[x].mf=t[x].ms=INF;return;}
    build(L,l,l+r>>1);build(R,(l+r>>1)+1,r);up(x);
}
void renew1(int x,int k,ll f)
{
    if(t[x].l==t[x].r){t[x].mf=t[x].ms=f;return;}
    down(x);renew1(k>t[x].l+t[x].r>>1?R:L,k,f);up(x);
}
void renew2(int x,int r,int a)
{
    if(t[x].mx<a&&t[x].r==r){mark(x,a);return;}
    if(t[x].l==t[x].r)return;down(x);
    int mid=t[x].l+t[x].r>>1;
    if(r<=mid)renew2(L,r,a);
    else if(t[R].mx>=a)renew2(R,r,a);
    else renew2(L,mid,a),renew2(R,r,a);
    up(x);
}
ll query(int x,int l,int r)
{
    if(t[x].l==l&&t[x].r==r)return t[x].ms;
    down(x);
    int mid=t[x].l+t[x].r>>1;
    if(r<=mid)return query(L,l,r);
    if(l>mid)return query(R,l,r);
    return min(query(L,l,mid),query(R,mid+1,r));
}
ll check(ll x)
{
    int i;
    build(1,1,n);renew1(1,1,0);
    for(i=1;i<=n;++i)
    {
        renew1(1,i,f[i-1]);
        renew2(1,i,a[i]);
        f[i]=query(1,lower_bound(sb,sb+n+1,sb[i]-x)-sb+1,i);
    }
    return f[n];
}
int main()
{
    freopen("sequence.in","r",stdin);
    freopen("sequence.out","w",stdout);int i,j,k,x;ll m,l=0,r,mid,ans;
    n=read();m=read();
    for(mb[0]=INF,i=1;i<=n;++i)a[i]=read(),mb[i]=min(mb[i-1],b[i]=read());
    for(i=n;i;--i)ma[i]=max(ma[i+1],a[i]);
    for(i=1,k=0;i<=n;i=j)
    {
        for(j=i,x=r=0;j==i||mb[j-1]<=ma[j];++j)x=max(x,a[j]),r+=b[j];
        a[++k]=x;b[k]=r;
    }
    for(n=k,i=1;i<=n;++i)sb[i]=sb[i-1]+b[i],l=max(l,b[i]);
    for(r=INF;l<=r;)if(check(mid=l+r>>1)<=m)ans=mid,r=mid-1;else l=mid+1;
    cout<<ans;
    fclose(stdin);fclose(stdout);return 0;
}
原文地址:https://www.cnblogs.com/ditoly/p/20170312C.html