尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

wqs二分学习笔记

wqs二分学习笔记
📅 发布时间:2026/6/17 23:59:36

一般解决问题

你有一个 \(k\),表示最后要变成 \(k\) 个,或者说是选 \(k\)。

形式化地讲,设 \(f(i)\) 表示最后变成 \(i\) 个,或者是选 \(i\) 个的方案。

你一般要求的是 \(f(k)\) 的最大值或者最小值。

问题特征

你最后的 \((x,f(x))\) 是一个凸包。

而凸性意味着:如果我们给每个被选的物品增加一个相同的额外代价/收益 \(\lambda\)(称为惩罚或奖励),那么最优解中选择的物品数量 \(g(\lambda)\) 会随着 \(\lambda\) 单调变化。

为什么,这就是他的原理。

首先我们有一个凸包,然后二分它的斜率,然后就相当于平移这个直线使它的截距最大或者最小,很明显与一个点相切。

求出这个点之后可以根据 \(x\) 继续二分,因为我们求的是 \(x=k\) 的情况。

这个点为 \((x,f(x))\),那么如果我让他每次选惩罚 \(\lambda\),那么它的值就为 \(0\) 了,但是在其它的点上面,惩罚过后都是 \(\leq 0\) 的,那么我当前这个就是要找的截距最大。

于是,我们把每个 \(-\lambda\) 放进去,那么我们所求的最大的(一般用 \(dp\))便是我们要找的 \(x\),基于此二分即可。

细节

这里需要考虑一些边界情况,wqs 二分两个极端是要么只要 \(1/0\) 个,要么全都要,依据这个就行了。

而且,你还需要考虑优化的 \(dp\) 算 \(x\) 的坐标一定要准确。

怎么判断是不是凸包呢?一种可用的方法是代价是凸函数,那么最后就是凸包,或者你可以求导解决。

例题

P4983 忘情

很好玩的题目。

题目概述

把长度为 \(n\) 的序列分成 \(k\) 个部分,每个部分的代价为 \((1+\sum_i a_i)^2\),那么最小的代价是多少呢?

分析

我们来思考一下。

我们注意到(\(\text{attention is all you need}\)),这个代价是单调的,也是凸的,所以可以用 wqs 二分解决。

最后我们求每一个少 \(\lambda\) 的 \(dp\),显然是斜率优化即可。

代码

时间复杂度 \(\mathcal{O}(n\log V)\) 的。

#include <iostream>
#include <cstdio>
#include <stdlib.h>
#include <algorithm>
#include <cstring>
#include <vector>
#define int long long
#define N 100005
#define sqr(x) (x) * (x)
using namespace std;
int n,m,f[N],a[N],q[N],sum[N],g[N];
double X(int id) {return sum[id];
}
double Y(int id) {return f[id] + sum[id] * sum[id] - 2 * sum[id];
}
double Slope(int fir,int sec) {return (Y(fir) - Y(sec)) / (X(fir) - X(sec));
}
void check(int mid) {memset(f,0x3f,sizeof f),memset(g,0,sizeof g);f[0] = 0;int head = 1,tail = 0;q[++tail] = 0;for (int i = 1;i <= n;i ++) {while(head < tail && Slope(q[head],q[head + 1]) < 2 * sum[i]) head ++;f[i] = f[q[head]] + sqr(sum[i] - sum[q[head]] + 1) + mid;g[i] = g[q[head]] + 1;while(head < tail && Slope(q[tail - 1],q[tail]) > Slope(q[tail],i)) tail --;q[++tail] = i;}
}
signed main(){cin >> n >> m;for (int i = 1;i <= n;i ++) {scanf("%lld",&a[i]);sum[i] = sum[i - 1] + a[i];}int l = 0,r = 1e18,res = 0;while (l <= r) {int mid = l + r >> 1;check(mid);if (g[n] <= m) r = mid - 1,res = mid;//x坐标不在要求的右边,那么我们求的x坐标要尽量靠左,因为如果你算的尽量靠右的话,有可能会被判掉else l = mid + 1;}check(res);cout << f[n] - m * res;return 0;
}

P2619 [国家集训队] Tree I

题目概述

给你一个带权无向连通图(有白边和黑边),恰好用 \(k\) 条白边的最小生成树。

分析

你可以通过打表或者怎么发现:一开始我限制了 \(\leq i\) 条白边,那么对于原本的最小生成树的白边数量 \(p\),如果 \(i\leq p\),那么单调下降,因为有些白边原本就可以替代一些黑边;如果 \(i> p\),那么单调上升,因为有些更优的黑边被你的白边给替代了。

于是我们就能通过此题了。

代码

时间复杂度 \(\mathcal{O}(n\log n\log V)\)。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <stdlib.h>
#include <algorithm>
#include <vector>
#define int long long
#define N 100005
using namespace std;
int n,m,k;
struct node{int u,v,w,col;
}a[N],b[N];
int fa[N];
int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);
}
int tj,ans;
void check(int mid) {tj = 0;ans = 0;for (int i = 1;i <= m;i ++) b[i] = a[i];for (int i = 1;i <= m;i ++)if (b[i].col == 0) b[i].w += mid;//更难被选到stable_sort(b + 1,b + 1 + m,[](node x,node y) {if (x.w == y.w) return x.col > y.col;//尽量少用return x.w < y.w;});for (int i = 1;i <= n;i ++) fa[i] = i;for (int i = 1;i <= m;i ++) {int x = b[i].u,y = b[i].v;int xx = find(x),yy = find(y);if (xx != yy) fa[xx] = fa[yy],tj += (b[i].col == 0),ans += b[i].w;}
}
signed main(){cin >> n >> m >> k;int cnt = 0;for (int i = 1;i <= m;i ++) {int u,v,col,w;scanf("%lld%lld%lld%lld",&u,&v,&w,&col);a[i] = {u + 1,v + 1,w,col};cnt += (col == 0);}// for (int i = 0;i <= cnt;i ++) {//     for (int j = 1;j <= n;j ++) fa[j] = j;//     int choose = 0,ans = 0;//     for (int j = 1;j <= m;j ++) {//         int x = a[i].u,y = a[i].v;//         int xx = find(x),yy = find(y);//         if (xx != yy) {//             if ((a[i].col == 0 && choose < i) || a[i].col == 1) fa[xx] = fa[yy],cnt += a[i].col == 0,ans += a[i].w;//         }//     }//     printf("%lld %lld\n",i,ans);// }// 从小到大,能用就用白的,但是不能超过限制,所以说前面的代价都是单调下降,到了极点,也就是原本最小生成树的白边个数后,它不得不用更大的白边去替换小的黑边,所以单调上升这是一个凸函数int l = -1e18,r = 1e18,res = -1e18;while(l <= r) {int mid = l + r >> 1;check(mid);if (tj <= k) r = mid - 1,res = mid;else l = mid + 1; }// cout << res << '\n';check(res);cout << ans - k * res;return 0;
}

先暂时更新到这里

相关新闻

  • Android系统中使用initrc脚本在开机时禁用selinux
  • 2025年10月氧化镁厂家最新推荐排行榜,轻烧氧化镁,重烧氧化镁,高纯氧化镁,活性氧化镁公司推荐!
  • Vector向量数据库对比

最新新闻

  • 2026年吉林职称代办选购指南:吉林工程师职称、长春职称申报、建筑职称咨询机构选择指南,服务、流程、合规三维度客观解析 - 海棠依旧大
  • 河北养鹿勾花网厂家实力排行:聚焦专业适配性 - 起跑123
  • VMware虚拟机安装Ubuntu 22.04 LTS全攻略:从配置优化到排错
  • 上海正规公司律师团队推荐 2026资质合规榜单一览 - 资讯纵览
  • 陇西宴席饭店深度测评|3家热门礼宴中心对比,办宴聚餐不踩坑 - 信息热点
  • MSC8144AMC-S高级夹层卡硬件架构与智能管理深度解析

日新闻

  • 2026年不锈钢卷板厂家推荐排行榜:冷轧热轧/304/201不锈钢卷板,高颜值耐腐蚀源头厂家实力精选 - 企业推荐官【官方】
  • FLUX.1-dev FP8模型实战指南:24GB以下显卡高效部署方案
  • 2026佛山长途搬家价目表:跨省跨市搬家费用完整计算指南 - 从来都是英雄出少年

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号