【学习笔记】浅谈闵可夫斯基和

学这东西主要是 这道题 要用 233

定义:给定两个凸包 A A A, B B B,定义 C = { a + b ∣ a ∈ A , b ∈ B } C=\{a+b|a\in A,b\in B\} C={a+baA,bB} ,其中 a a a, b b b均为坐标。

不好意思图是嫖的

在这里插入图片描述
首先我们感性认识一下。可以直接将一个凸包的顶点换成另一个凸包,然后保留外层凸包。

在这里插入图片描述
于是我们看出来合并后凸包大小为 ∣ A ∣ + ∣ B ∣ |A|+|B| A+B。可以看成从一个凸包跳到另一个凸包再跳回来。

对于下凸壳闵可夫斯基和,下凸壳就是凸壳下部分的点集,可以看成被下方平行光照射的部分。

在这里插入图片描述

可以发现其本质就是差分数组合并后的结果。复杂度 O ( ∣ A ∣ + ∣ B ∣ ) O(|A|+|B|) O(A+B)

回到 假人 这道题。我们知道结论 f ( i ) f(i) f(i)按模 12 12 12分组构成凸包,这启发我们采用分治算法,用闵可夫斯基和将左右凸包两两合并即可。

代码咕了。

代码来了。借鉴了一下std的做法。

#include<bits/stdc++.h>
#define fi first
#define se second
#define ll long long
#define pb push_back
#define db double
#define mp make_pair
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
int n,m,ps[100005];
vector<int>a[100005];
struct Data{
	vector<ll>vec[12];
};
void chmax(ll &x,ll y){x=max(x,y);}
inline void Merge(const Data &a, const Data &b, Data &c) {
	for (int i = 0; i < 12; i++) if (a.vec[i].size()) {
		for (int j = 0; j < 12; j++) if (b.vec[j].size()) {
			int dlt = (i + j >= 12), k = (i + j) % 12;
			int x = 0, y = 0;
			while (true) {
				chmax(c.vec[k][x + y + dlt], a.vec[i][x] + b.vec[j][y]);
				if (x == (int)a.vec[i].size() - 1 && y == (int)b.vec[j].size() - 1) break;
				if (x == (int)a.vec[i].size() - 1) y++;
				else if (y == (int)b.vec[j].size() - 1) x++;
				else {
					if (a.vec[i][x + 1] - a.vec[i][x] > b.vec[j][y + 1] - b.vec[j][y]) x++;
					else y++;
				}
			}
		}
	}
}
Data solve(int l, int r) {
	if (l == r) {
		Data ret;
		for (int i = 0; i < (int)a[l].size(); i++) ret.vec[i].push_back(a[l][i]);
		return ret;
	}
	int mid = (l + r) >> 1;
	Data a = solve(l, mid), b = solve(mid + 1, r), ret;
	for (int i = 0; i < 12; i++) {
		for (int j = i; j <= ps[r] - ps[l - 1]; j += 12) {
			ret.vec[i].push_back(-1);
		}
	}
	Merge(a, b, ret);
	return ret;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n;for(int i=1;i<=n;i++){
		int k;cin>>k,m+=k,ps[i]=ps[i-1]+k-1;for(int j=0;j<k;j++){
			int x;cin>>x,a[i].pb(x);
		}
	}Data res=solve(1,n);
	for(int i=0;i<=m-n;i++)cout<<res.vec[i%12][i/12]<<" ";
}
  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值