首页 > 其他分享 >[JOISC2017] Cultivation

[JOISC2017] Cultivation

时间:2024-08-13 16:27:27浏览次数:6  
标签:sy JOISC2017 边界 int mn Cultivation 矩形 cur

link

不是,怎么四方跑得飞快啊?成最优解了?有人会卡吗?鉴定为剪枝太多导致的。

一个出发点不太一样的思路。假设上下左右各被操作了 \(U,D,L,R\) 次。我们考虑一个点 \((x,y)\) 不被感染的条件是初始时 \([x-D,x+U]\times [y-R,y+L]\) 这个矩形内没有任何感染点。

考虑扣出所有中间没有感染点的极大矩形,极大矩形的定义是所有边界上要么挨着一个感染点要么是全局边界的矩形。这样的矩形至多只有 \(O(n^2)\) 种。为什么呢?考虑怎么扣出这些矩形,你枚举上边界顶到的点(或者是全局的上边界),然后对其严格下面所有点按 \(x\) 坐标建小根笛卡尔树,那么其 \(y\) 坐标所在的那一条链上每一个节点对应着一个极大矩形(如果是全局边界那么所有点都对应一个矩形)。自然有上界 \(O(n^2)\)。

同时这个过程也告诉我们四个边界包含至少一个全局边界的极大矩形是 \(O(n)\) 级别的。

考虑一个极大矩形对于 \(U,D,L,R\) 的限制,如果四面都是被感染点限制的,那么限制形如 \(U+D\le lenx\) 和 \(L+R\le leny\) 不能同时成立。但是如果有一面是全局边界,那么事实上这一面中矩形超过外边界是合法的,即限制可能变成了单独的 \(U/D\le lenx\) 或 \(L/R\le leny\) 的形式。

然后发现如果用 DS 维护这个东西有点 dirty,索性暴力枚举,即排序所有限制后暴力枚举 \(U,D,U+D\) 所在的限制区间,就推导出 \(L,R,L+R\) 分别的下界,取最小的 \(L+R\) 更新答案即可。

\(U,D\) 限制个数各 \(O(n)\) 种,\(U+D\) 限制个数可能达到 \(O(n^2)\),所以理论复杂度 \(O(n^4)\)。但是出题人完全没卡极大矩形个数,所以这个做法表现跟平方差不多,结果十几毫秒断崖式最优解。

当然这个算法比较暴力,我觉得很有可能可以继续用 DS 优化。

#include <array>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
int read(){
	char c=getchar();int x=0;
	while(c<48||c>57) c=getchar();
	do x=x*10+(c^48),c=getchar();
	while(c>=48&&c<=57);
	return x;
}
typedef long long ll;
const int N=303,T=200003;
const ll INF=0x3f3f3f3f3f3f3f3f;
typedef array<ll,3> arr;
typedef vector<int> vi;
int R,C,n,cur;ll res=INF;
int sx[N],sy[N];
arr X,Y;
inline void chmx(ll &x,ll v){if(x<v) x=v;}
inline void chmn(ll &x,ll v){if(x>v) x=v;}
struct node{
	ll u,v;int d;
	friend bool operator<(const node a,const node b){
		return a.u<b.u;
	}
}S[3][T];arr W;
inline int judgex(int xl,int xr){
	if(xl==1&&xr==R) return -1;
	if(xl==1) return 0;
	if(xr==R) return 1;
	return 2;
}
inline int judgey(int yl,int yr){
	if(yl==1&&yr==C) return -1;
	if(yl==1) return 0;
	if(yr==C) return 1;
	return 2;
}
void opt(int xl,int xr,int yl,int yr){
	int lenx=xr-xl+1,leny=yr-yl+1;
	int jx=judgex(xl,xr),jy=judgey(yl,yr);
	if(jx<0) return chmx(Y[jy],leny);
	if(jy<0) return chmx(X[jx],lenx);
	S[jx][W[jx]++]=(node){lenx,leny,jy};
}
void solve(int l,int r,vi vc,int las){
	if(vc.empty()) return opt(sx[cur]+1,R,l,r);
	int mn=vc.front();
	for(int x:vc) if(sx[x]<sx[mn]) mn=x;
	if(sx[cur]<sx[mn]-1&&sx[mn]>las) opt(sx[cur]+1,sx[mn]-1,l,r);
	if((!cur||sy[cur]<sy[mn])&&l<sy[mn]){
		vi tmp;
		for(int x:vc) if(sy[x]<sy[mn]) tmp.emplace_back(x);
		solve(l,sy[mn]-1,tmp,sx[mn]);
	}
	if((!cur||sy[cur]>sy[mn])&&sy[mn]<r){
		vi tmp;
		for(int x:vc) if(sy[x]>sy[mn]) tmp.emplace_back(x);
		solve(sy[mn]+1,r,tmp,sx[mn]);
	}
}
int main(){
	R=read();C=read();n=read();
	for(int i=1;i<=n;++i) sx[i]=read(),sy[i]=read();
	vi init;
	for(int i=1;i<=n;++i){
		if(sx[i]==R) continue;
		for(int j=1;j<=n;++j)
			if(sx[j]>sx[i]) init.emplace_back(j);
		cur=i;solve(1,C,init,0);init.clear();
	}
	for(int i=1;i<=n;++i) init.emplace_back(i);
	cur=0;solve(1,C,init,0);
	for(int t=0;t<3;++t) sort(S[t],S[t]+W[t]),S[t][W[t]].u=INF;
	arr Yi=Y;
	for(int i=W[0];~i;--i){
		if(i<W[0]) chmx(Yi[S[0][i].d],S[0][i].v);
		ll l0=X[0],r0=S[0][i].u-1;
		if(l0>r0) break;
		if(i) chmx(l0,S[0][i-1].u);
		if(l0>r0) continue;
		arr Yj=Yi;
		for(int j=W[1];~j;--j){
			if(j<W[1]) chmx(Yj[S[1][j].d],S[1][j].v);
			ll l1=X[1],r1=S[1][j].u-1;
			if(l1>r1) break;
			if(j) chmx(l1,S[1][j-1].u);
			if(l1>r1) continue;
			arr Yk=Yj;
			for(int k=W[2];~k;--k){
				if(k<W[2]) chmx(Yk[S[2][k].d],S[2][k].v);
				ll l2=X[2],r2=S[2][k].u-1;
				if(l2>r2) break;
				if(k) chmx(l2,S[2][k-1].u);
				if(l2>r2||l2>r0+r1) continue;
				if(r2<l0+l1) break;
				chmn(res,max(Yk[0]+Yk[1],Yk[2])+max(l0+l1,l2));
			}
		}
	}
	printf("%lld\n",res);
	return 0;
}

标签:sy,JOISC2017,边界,int,mn,Cultivation,矩形,cur
From: https://www.cnblogs.com/yyyyxh/p/18357219/cultivation

相关文章

  • joisc2017 D3T1 长途巴士 题解
    joisc2017D3T1长途巴士题解这是学校ACM欢乐赛的题,赛时想到做法了,但是因为我各种唐诗没写出来翻了转化题面我们发现,只可以踢掉检查站前面一个连续段的接水人,并且不能踢掉司机,考虑画出对整个路程表示的线段上图几个小点是检查点,考虑在每个检查点之前踢掉一段的人,容易发......
  • 「JOISC2017」门票安排
    题目点这里看题目。分析不妨先认为\(C_i=1\)。首先破环为链,则原问题等价于:你有一个长度为\(n\)的序列\(a\)和\(m\)个二元组\((l_i,r_i)\)。一开始时,\(a_i=0\)......
  • JOISC2017 门票安排
    肯定先考虑二分答案,判定能不能全部不超过\(w\)。钦定不走\(n\rightarrow1\)的边,接着翻转若干区间。翻转一个区间的变化是\([1,l)++,[l,r)--,[r,n]++\)。注意到翻转......
  • JOISC2017j 誘拐 2 (Abduction 2)
    \(\mathcalLink\)做法一现考虑一个人的情况。设\(f_{i,j,0/1}\)表示从\((i,j)\)开始沿横/竖方向走的最大距离。走到下一个位置相当于在其中一个数组中向左/右找第......