bzoj2369 && 2687 -- 决策单调性优化DP

10 篇文章 0 订阅
6 篇文章 0 订阅

显然只选 2 个区间是最优的,因为取一个集合中所有区间一定没有只取最左和最右两个区间优。
对于那些有包含关系的区间,更新一下答案,只留下最大的区间就可以了。
将区间按左端点排序。
设第 i 个区间为 [li,ri] 。可以发现若 p<k<i<j ,且对于 i 来说 k p 优,那么对于 j 来说 k 也比 p 优。
证明如下:

(rilk)(rkli)>(rilp)(rpli)

ri(rkrp)+li(lklp)>lkrklprp

由于 l r 都是单调递增的 , 所以
rj(rkrp)+lj(lklp)>lkrklprp

(rjlk)(rklj)>(rjlp)(rplj)

所以对于 j 来说 k p <script type="math/tex" id="MathJax-Element-266">p</script> 优。
由于不用在线,可以用分治做决策单调性。注意判断两个区间是否有交。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
inline 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());
}
#define N 1000010
#define ll long long
struct Node{
    int l,r;
}a[N],b[N];
int i,j,k,n,m,p,mx,x;
ll Ans;
inline bool Cmp(Node a,Node b){
    if(a.l==b.l)return a.r>b.r;
    return a.l<b.l;
}
inline void Solve(int l,int r,int L,int R){
    if(l>r)return;
    int Mid=l+r>>1,x=0;
    ll mx=0;
    for(int i=min(R,Mid-1);i>=L&&b[i].r>b[Mid].l;i--){
        ll t=1ll*(b[Mid].r-b[i].l)*(b[i].r-b[Mid].l);
        if(t>mx)mx=t,x=i;
    }
    Ans=max(Ans,mx);
    if(!x)Solve(l,Mid-1,L,R),Solve(Mid+1,r,L,R);else
    Solve(l,Mid-1,L,x),Solve(Mid+1,r,x,R);
}
int main(){
    Read(n);
    for(i=1;i<=n;i++)Read(a[i].l),Read(a[i].r);
    sort(a+1,a+n+1,Cmp);
    mx=a[1].r;x=1;
    b[m=1]=a[1];
    for(i=2;i<=n;i++)
    if(a[i].r>mx)mx=a[i].r,b[++m]=a[i],x=i;else
    Ans=max(Ans,1ll*(a[i].r-a[i].l)*(a[x].r-a[x].l));
    Solve(2,m,1,m);
    cout<<Ans<<endl;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值