[LOJ3192] 「ROI 2019 Day2」课桌

前言

我收回上一篇题解的话,这题我自己做复杂度铁定优化不下去,本地最多 (94pts)

但是没有时间,只拿了 (12pts),亏大了。

题目

LOJ

讲解

这题其实就利用一个东西:单调性。

我个人认为这题的结论应该比较显然。

排除掉完全没用的桌子(范围被其它桌子完全包含),假如我们已经选好了桌子,将桌子按左端点排序后,每组的学生也应该按高度从低到高坐到座位上。

此时我们不再把学生分为 (m) 组,因为组内没什么联系,我们将坐在同一张桌子的同学视为一组,共有 (2m) 组,每组 (n) 个同学。

每组同学使用同一张桌子,这 (2m) 组使用的桌子按左端点单调不降。

然后我们直接对新定义的组分治,求出中间那个组的贡献之后,由于桌子也是单调的,往两边分治就好了。

用飘飘蛋的话来说:实现的时候要精细一点,用 two-pointer 可以显著降低复杂度。

时间复杂度 (O((k+nm)log_2n))

代码

不精细的实现
//12252024832524
#include <bits/stdc++.h>
#define TT template<typename T>
using namespace std;

typedef long long LL;
const int MAXN = 200005;
const LL INF = 1ll << 60;
int m,n,k;
int o[MAXN << 1]; 
bool tag[MAXN];
struct desk
{
	int l,r;
	bool operator < (const desk &px)const{
		if(l^px.l) return l < px.l;
		return r > px.r;
	}
}d[MAXN];
vector<desk> a[MAXN];

LL Read()
{
	LL x = 0,f = 1; char c = getchar();
	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
	return x * f;
}
TT void Put1(T x)
{
	if(x > 9) Put1(x/10);
	putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
	if(x < 0) putchar('-'),x = -x;
	Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}

LL Get(desk stu,desk des)//student & desk
{
	LL ret = 0;
	if(stu.l < des.l) ret += des.l - stu.l;
	if(stu.l > des.r) ret += stu.l - des.r;
	if(stu.r < des.l) ret += des.l - stu.r;
	if(stu.r > des.r) ret += stu.r - des.r;
	return ret;
}
LL solve(int sl,int sr,int dl,int dr)//student lr,desk lr,好像是个暴力吧? LOJ有78 (Ofast)
{
	if(sl > sr) return 0;
	LL ret = 0;
	if(dl == dr)
	{
		for(int i = 1;i <= m;++ i)
			for(int j = sl;j <= sr;++ j)
				ret += Get(a[i][j],d[dl]);
		return ret;
	}
	int mid = (sl+sr) >> 1,B = dl; LL MIN = INF;
	for(int i = dl;i <= dr;++ i)
	{
		LL cur = 0;
		for(int j = 1;j <= m;++ j) cur += Get(a[j][mid],d[i]);
		if(cur < MIN) B = i,MIN = cur;
	}
	return MIN+solve(sl,mid-1,dl,B)+solve(mid+1,sr,B,dr);
}

int main()
{
//	freopen("party.in","r",stdin);
//	freopen("party.out","w",stdout);
	m = Read(); n = Read(); k = Read();
	for(int i = 1;i <= k;++ i) d[i].l = Read(),d[i].r = Read();
	sort(d+1,d+k+1);
	int R = 0;
	for(int i = 1;i <= k;++ i)
	{
		if(R >= d[i].r) tag[i] = 1;
		R = Max(R,d[i].r);
	}
	int kk = k; k = 0;
	for(int i = 1;i <= kk;++ i) if(!tag[i]) d[++k] = d[i];
	for(int i = 1;i <= m;++ i)
	{
		for(int j = 0;j < (n<<1);++ j) o[j] = Read();
		sort(o,o+(n<<1));
		for(int j = 0;j < (n<<1);j += 2) a[i].emplace_back(desk{o[j],o[j+1]});
	}
	Put(solve(0,n-1,1,k),'
');
	return 0;
}
精细的实现
//12252024832524
#include <bits/stdc++.h>
#define TT template<typename T>
using namespace std;

typedef long long LL;
const int MAXN = 200005;
const LL INF = 1ll << 60;
int m,n,k;
int o[MAXN << 1]; 
bool tag[MAXN];
struct desk
{
	int l,r;
	bool operator < (const desk &px)const{
		if(l^px.l) return l < px.l;
		return r > px.r;
	}
}d[MAXN];
vector<desk> a[MAXN];
vector<int> fs[MAXN];//final students list

LL Read()
{
	LL x = 0,f = 1; char c = getchar();
	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
	return x * f;
}
TT void Put1(T x)
{
	if(x > 9) Put1(x/10);
	putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
	if(x < 0) putchar('-'),x = -x;
	Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}

LL Get(int h,desk des)//student & desk
{
	if(h < des.l) return des.l - h;
	if(h > des.r) return h - des.r;
	return 0;
}
LL pre[MAXN << 1];
LL Query(int l,int r)
{
	if(l > r) return 0;
	LL ret = pre[r];
	if(!l) return ret;
	return ret - pre[l-1];
}
LL solve(int sl,int sr,int dl,int dr)//student lr,desk lr,O((k+nm)log_2n)
{
	if(sl > sr) return 0;
	LL cur = 0,MIN = INF;
	int lid = 0,rid = 0,B = dl,mid = (sl+sr) >> 1;
	for(int i = 0;i < (m<<1);++ i) pre[i] = ((i ? pre[i-1] : 0) + fs[mid][i]);
	for(int i = dl;i <= dr;++ i)
	{
		while(lid < (m<<1) && fs[mid][lid] < d[i].l) ++lid;
		while(rid < (m<<1) && fs[mid][rid] <= d[i].r) ++rid;
		cur = 1ll * d[i].l * lid - Query(0,lid-1) + Query(rid,(m<<1)-1) - 1ll * ((m<<1)-rid) * d[i].r;
		if(cur < MIN) MIN = cur,B = i;
	}
	return MIN+solve(sl,mid-1,dl,B)+solve(mid+1,sr,B,dr);
}

int main()
{
//	freopen("party.in","r",stdin);
//	freopen("party.out","w",stdout);
	m = Read(); n = Read(); k = Read();
	for(int i = 1;i <= k;++ i) d[i].l = Read(),d[i].r = Read();
	sort(d+1,d+k+1);
	int R = 0;
	for(int i = 1;i <= k;++ i)
	{
		if(R >= d[i].r) tag[i] = 1;
		R = Max(R,d[i].r);
	}
	int kk = k; k = 0;
	for(int i = 1;i <= kk;++ i) if(!tag[i]) d[++k] = d[i];
	for(int i = 1;i <= m;++ i)
	{
		for(int j = 0;j < (n<<1);++ j) o[j] = Read();
		sort(o,o+(n<<1));
		for(int j = 0;j < (n<<1);j += 2) fs[j >> 1].emplace_back(o[j]),fs[j >> 1].emplace_back(o[j+1]);
	}
	for(int i = 0;i < n;++ i) sort(fs[i].begin(),fs[i].end());
	Put(solve(0,n-1,1,k),'
');
	return 0;
}
原文地址:https://www.cnblogs.com/PPLPPL/p/15412433.html