首页 > 其他分享 >P5896 [IOI2016] aliens (斜率优化 dp+wqs 二分)

P5896 [IOI2016] aliens (斜率优化 dp+wqs 二分)

时间:2024-04-29 10:26:56浏览次数:22  
标签:return qt P5896 int aliens wqs long ++ ll

我们可以把所有点都对称到主对角线下方。

然后每个点如果想被覆盖都会有一个最小的三角形,我们可以贪心的只留必须选的点。如果把剩下的点按 \(x\) 坐标升序排序,可以发现他们的 \(y\) 坐标也是升序排序的。

记剩余点个数为 \(n\),显然每个点都选自己的最小三角形最好。但是有可能 \(n>K\),即我们不得不合并一些连续的最小三角形。可以 \(dp\),\(f_{i,k}\) 表示覆盖前 \(i\) 个点,用了 \(k\) 个三角形的最少覆盖点。枚举 \(j\),把 \(j+1\sim i\) 用一个三角形覆盖,转移即可。

\[f_{i,k}={f_{j,k−1}+(x_i−y_j+1+1)}^2 \]

注意处理重叠的点,要减去这些点,可以直接记在 \(f_{j,k-1}\) 里。

发现可以斜率优化,\(O(n\times k)\)。

还是过不去,我们考虑 wqs 二分,降维打击!
复杂度 \(O (n \log m)\)

#include <bits/stdc++.h>
using namespace std;
#define N 100010
#define ll long long
#define inf 0x3f3f3f3f
struct P {
	int x, y;
} p[N];
inline bool cmp(P a, P b) {
	return a.x == b.x ? a.y > b.y : a.x < b.x;
}
inline ll sqr(ll x) {
	return x * x;
}
ll f[N];
int cnt[N], q[N], qh, qt;
inline double slope(int k1, int k2) {
	return (f[k2] - f[k1] + sqr(p[k2 + 1].y) - sqr(p[k1 + 1].y)) * 1.0 / (2 * (p[k2 + 1].y - p[k1 + 1].y));
}
inline int solve(int n, ll C) {
	qh = 1;
	qt = 0;
	q[++qt] = 0;
	for (int i = 1; i <= n; ++i) {
		while (qh < qt && slope(q[qh], q[qh + 1]) < p[i].x + 1) ++qh;
		f[i] = f[q[qh]] + sqr(p[i].x - p[q[qh] + 1].y + 1) + C, cnt[i] = cnt[q[qh]] + 1;
		if (i == n) break;
		if (p[i + 1].y <= p[i].x) f[i] -= sqr(p[i].x - p[i + 1].y + 1);
		while (qh < qt && slope(q[qt - 1], q[qt]) > slope(q[qt], i)) --qt;
		q[++qt] = i;
	}
	return cnt[n];
}
long long take_photos(int n, int m, int k, std::vector<int> r, std::vector<int> c) {
	ll ans = 0, l = 0, rr = (ll)m * m + 10;
	for (int i = 0; i < n; ++i) {
		if (r[i] < c[i]) p[i + 1].x = c[i], p[i + 1].y = r[i];
		else p[i + 1].x = r[i], p[i + 1].y = c[i];
	}
	sort(p + 1, p + n + 1, cmp);
	m = 0;
	p[0].y = -1;
	for (int i = 1; i <= n; ++i) {
		while (m && p[m].y >= p[i].y) --m;
		p[++m] = p[i];
	}
	n = m;
	for (int i = 1; i <= n; ++i) {
		ans += sqr(p[i].x - p[i].y + 1);
		if (i < n && p[i + 1].y <= p[i].x) ans -= sqr(p[i].x - p[i + 1].y + 1);
	}
	if (n <= k) return ans;
	while (l <= rr) {
		ll mid = l + rr >> 1;
		int res = solve(n, mid);
		if (res <= k) rr = mid - 1, ans = f[n];
		else l = mid + 1;
	}
	rr++;
	ans -= rr * k;
	return ans;
}

标签:return,qt,P5896,int,aliens,wqs,long,++,ll
From: https://www.cnblogs.com/BadBadBad/p/18165074/P5896

相关文章

  • [dp 小计] wqs 二分
    天才算法!国外叫Alienstrick(外星人trick),真的太强了。其实是因为IOI2016Aliens这道题考了这个算法才开始普及。解决问题wqs二分一般用来解决如下问题。给定\(n\)个数,求强制选\(m\)个的价值最大。如果不是强制选\(m\)个,这类问题很好做。现在问题就是怎么取消......
  • WQS 二分
    一个参考WQS二分用来处理一些答案构成凸函数的问题。最经典、最常见的形式,就是"从若干个物品中恰好选给定个数的最优"型问题。适用要求:如果不考虑选的物品的个数限制,可以很快求出答案。例题:P2619TreeI从所有白边中选\(need\)条,然后加上若干条黑边形成生成树,最优是多......
  • wqs二分
    https://zhuanlan.zhihu.com/p/340514421https://blog.csdn.net/Emm_Titan/article/details/124035796https://www.cnblogs.com/TianMeng-hyl/p/14972355.htmlhttps://www.cnblogs.com/Liang-sheng/p/15182786.html......
  • wqs二分学习笔记
    wqs二分wqs是用来处理一类带有恰好选K个这种限制的问题我们如果发现这个答案关于k的函数是凸函数,那么就可以二分出斜率,然后拿它去切这个函数设这个直线为\(y=ax+b\),以上凸为例,我们要求截距最大,就是b最大,等价于\(y-ax\)最大,也就是把k限制对应的贡献-a,然后再算答案,然后就可以去......
  • WQS二分学习笔记
    WQS二分WQS二分是一种可以处理一类带有限制的问题的方法,这种限制一般是恰好选\(k\)个的形式,而且要求原问题有凸性。比如函数是上凸的,那么斜率就递减,如果我们去二分这个斜率,那么可以快速求出切点,而切点横坐标代表我们选择了多少个,于是我们就可以根据这个数目和题中要求的\(k\)......
  • IOI 2007 Aliens
    今天开始做IOI的学习笔记,就从我出生的年份开始吧IOI2007Aliens:给你三个整数N,X,Y表示网格有N*N大,而(X,Y)是黑色的图那个图是这样的:#.#.#.#.#.#.#.#.#.#.#.#.# #表示黑色 .表示白色而整个N*N的网格只有一个这样的图形,每个箱子有一个偶数M为长度......
  • 关于 wqs 二分的几何意义的思考
    我们知道,wqs二分是通过二分斜率,通过找到切凸包的切点来寻找答案(至少我目前写的简单题是这样的)。那么所谓切凸包的几何意义是什么?我们以LGP5633最小度限制生成树为例。对于样例,我们设\(f(x)\)为节点\(s\)恰为\(x\)度的情况下最小生成树的权值,画出凸包。由于偏移量是......
  • 浅谈WQS二分
    WQS二分学习笔记目录WQS二分学习笔记用途:思考方式:使用限制:算法思想:用途:WQS二分通常用来解决形如强制选k个且收益最大/代价最小的题目。就比如说:https://www.luogu.com.cn/problem/P5308如果没有限制的话,代码会非常简单思考方式:使用限制:首先要使用WQS二分要有限制:便是最终k......
  • Vulnhub: hacksudo: aliens靶机
    kali:192.168.111.111靶机:192.168.111.175信息收集端口扫描nmap-A-sC-v-sV-T5-p---script=http-enum192.168.111.175目标80端口backup目录存在文件mysql.bak,下载后查看获得mysql账号密码登录9000端口的phpmyadmin,执行sql语句写入webshellselect'<?phpsystem($......