WQS二分/带权二分/凸优化DP
发布日期:2021-06-30 10:32:43 浏览次数:3 分类:技术文章

本文共 1680 字,大约阅读时间需要 5 分钟。

n n n个物品,限定选择 m m m个物品求最大/最小权值。

当然具体怎么计算权值按照题目的意思来定

g ( x ) g(x) g(x)表示强制选择 x x x个物品能得到的最大权值

( x , g ( x ) ) (x,g(x)) (x,g(x))在平面上形成一个凸函数,就可以使用 w q s wqs wqs二分


思想是,我们知道这个凸包的大概形状,但是不知道具体的点 ( x , g ( x ) ) (x,g(x)) (x,g(x))(直接求复杂度高)

考虑用一条斜率为 k k k的直线去切这个凸包,可以得到一个切点,满足过这个切点截距最大

设这条直线是 y = k x + b y=kx+b y=kx+b,设过点 ( x , g ( x ) ) (x,g(x)) (x,g(x)),那么可以计算出截距 b = g ( x ) − k x b=g(x)-kx b=g(x)kx

现在让 b b b最大的时候就是切点,也就是当 g ( x ) − k x g(x)-kx g(x)kx最大时的 x x x

观察 k x kx kx这一项,可以看成每多选一个物品获得 − k -k k的权值

于是我们先把所有物品权值减去 k k k然后求 g ( x ) g(x) g(x)的最大值即可

由于不限制选几个物品,所以 g ( x ) g(x) g(x)的最大值一般能在 O ( n ) O(n) O(n)的时间内求得,同时可以得到此时取到最大的 x x x

现在有什么用呢??

我们知道,由于这是一个上凸壳,斜率递减,所以随着斜率 k k k的减小而增大

这是由单调性的,所以可以根据我们每次的切点在 m m m左边还是右边来二分

这样当我们找到 x = m x=m x=m时,就找到了这个点

一个例题

感性理解,设 g ( x ) g(x) g(x)表示生成树中含有 x x x条白边的生成树权值

那么 g ( x ) g(x) g(x)一定是一个下凸函数,因为前面选的白边少,所以有更多黑边的选择空间…

我们尝试用斜率 k k k的直接切这个凸包

b = g ( x ) − k x b=g(x)-kx b=g(x)kx

所以先给每条边减去 k k k的权值,然后跑普通的最小生成树得到 b b b,记此时的 x x x r e s res res

下凸壳的斜率是递增的,所以随着 k k k的递增切点 x x x也是递增的,具备单调性

r e s < n e e d res<need res<need时,显然 k k k往右边二分

r e s > = n e e d res>=need res>=need时, k k k往左边二分

这样最后可以二分到 n e e d need need

#include 
using namespace std;const int maxn = 5e6+10;int n,m,ned,fa[maxn],cost;struct edge{
int l,r,w,type; bool operator < ( const edge&tmp ) const {
if( w!=tmp.w ) return w
> n >> m >> ned; for(int i=1;i<=m;i++) {
cin >> a[i].l >> a[i].r >> a[i].w >> a[i].type; a[i].l++; a[i].r++; } sort( a+1,a+1+m ); int l = -100, r = 100, ans = 0; while( r>=l ) {
int mid = (l+r)/2; if( isok(mid)>=ned )//二分的点在左边,斜率应该减小 r = mid-1, ans = cost+mid*ned; else l = mid+1; } cout << ans;}

转载地址:https://issue-is-vegetable.blog.csdn.net/article/details/116307738 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:P5785 [SDOI2012]任务安排(斜率优化+二分下凸壳)
下一篇:P3628 [APIO2010]特别行动队(简单斜率优化)

发表评论

最新留言

做的很好,不错不错
[***.243.131.199]2024年04月23日 01时16分36秒