description
给定段区间。从中选择若干段(至少2段)区间,最大化它们的交集长度与并集长度的乘积。
solution
首先只会选恰好2段。
因为如果选多段,删边不会让交集长度变小,留下左端点最小的边和右端点最大的边并集也不会改变,所以可以用2段替代不劣与多段。
分类讨论两端关系
- 包含:
按r从小到大排序(r相等按l从大到小排序),然后树状数组维护左端点的最大len,每次查询时,所有它能包含的都已经在树状数组里了,只用查询左端点>=它的左端点的maxlen,然后乘自己的长度即可。就需要后缀max树状数组。 - 不包含:
首先满足包含关系的一对区间删去短的一段,构成了和都单增的不存在包含关系的区间。
此时对于选择区间答案是
还要,不相交,发现答案值是负数不影响结果。
此时这个类似二次函数的东西是有决策单调性(单增)。我不会证!不会!
于是整体二分即可。
code
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e6+5;
struct node {int l,r;}Q[N],A[N];
bool cmp(node u,node v) {return u.r==v.r?u.l>v.l:u.r<v.r;}
int n,mnL[N],m,up;
ll ans;
int cmx[N];
void Update(int u,int d) {for(;u;u-=u&(-u))cmx[u]=max(cmx[u],d);}
int Ask(int u) {int mx=0;for(;u<=up;u+=u&(-u))mx=max(mx,cmx[u]);return mx;}
void init() {
scanf("%d",&n);up=0;
for(int i=1;i<=n;i++) scanf("%d%d",&Q[i].l,&Q[i].r),Q[i].l+=1e6,Q[i].r+=1e6,up=max(up,Q[i].r);
sort(Q+1,Q+1+n,cmp);
mnL[n+1]=1e9;for(int i=n;i;i--)mnL[i]=min(Q[i].l,mnL[i+1]);
for(int i=1;i<=n;i++) {
int len=Q[i].r-Q[i].l;
if(Q[i].l==Q[i+1].l&&Q[i].r==Q[i+1].r) {ans=max(ans,1ll*len*len);}
if(mnL[i+1]>Q[i].l) {ans=max(ans,1ll*len*Ask(Q[i].l));A[++m]=Q[i];}
else Update(Q[i].l,len);
}
}
ll calc(int j,int i) {
return 1ll*(A[i].r-A[j].l)*(A[j].r-A[i].l);
}
void solve(int L,int R,int l,int r) {
if(l>r)return;
if(L==R) {for(int i=l;i<=r;i++)ans=max(ans,calc(L,i));return;}
int mid=(l+r)>>1,pos;ll mx=-1e18;
for(int i=L;i<=min(mid-1,R);i++) {
ll w=calc(i,mid);
if(mx<w) {
mx=w;pos=i;
}
}
ans=max(ans,mx);
solve(L,pos,l,mid-1);solve(pos,R,mid+1,r);
}
int main() {
init();
solve(1,m-1,2,m);
printf("%lld\n",ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人