LOJ2390 「JOISC 2017 Day 1」开荒者


能否证明,我们一定是横向或纵向填满之后再移动另一个维度的?

相当于你是将每一个都扩展成一个相同大小的矩形,同时能覆盖整个大矩形,问你矩形最小的周长是多少。
那我们对四个角分别找出到达的限制即可?不对。

当然存在一个暴力的想法就是枚举这个最终的矩阵,但是显然是不能通过的。


考虑如果我们已经确定了矩阵的上下距离,那么如何确定左右的范围呢?实际上就是一个扫描线,然后根据扫描到的东西更新即可。

再略加思考,左右的移动数量实际上只和上下界的和有关,我们不妨考虑枚举上下界的和,然后在其中找到一个长度为 R 的段,满足左右的移动最小。

我们考虑不断加长上下界的和的时候,所有段的相对顺序是不会变的,会变的是一些段的左端点和另一些段的右端点之间的顺序交换。

我们考虑这个交换次数最多只会出现 \(O(n^2)\) 次,我们暴力 \(O(n)\) 修改,每次修改之后用三个单调队列查询即可。

考虑关键点的加入不仅仅是端点位置的变化,同时还有答案可能的取值点,应该就是单个节点顶牢上下界的情况和两个节点分别顶牢上下界的情况。

被卡常了,??????????????????

#include
using namespace std;
#define uint unsigned
const int N=3e2+5;
const uint INF=2e9+7;
uint r,c,X[N];int n,m;
unordered_map mp;
struct Seed{uint x,y;}a[N];
bool cmp(Seed a,Seed b){return a.x!=b.x?a.x bag[N<<1];multiset res[N<<1];
vector bag[N<<1];
uint L[N<<1],R[N<<1],mx[N<<1];
struct Opt{int id;uint x,t;};
bool operator < (Opt a,Opt b){return a.t>b.t;}
priority_queue q;
uint ans=INF;
void Work(int id){
	L[id]=bag[id].front()-1,R[id]=c-bag[id].back(),mx[id]=0;
	for(int i=1;i<(int)bag[id].size();++i) mx[id]=max(mx[id],bag[id][i]-bag[id][i-1]-1);
}
void INSERT(int id,uint x){
	for(int i=0;i<(int)bag[id].size();++i){
		if(x==bag[id][i]) return ;
		if(x>1]+1+T;
	else return X[id>>1];
}
int get_nxt(int &i,int &j,uint T){
	if(i<=m&&j<=m){
		if(X[i] a;
	for(int i=1,j=1,k=get_nxt(i,j,T);k;k=get_nxt(i,j,T)) a.push_back(k);
	for(int i=0,j=0;i+1<(int)a.size();++i){
		while(get_dis(a[i],T)-get_dis(a[j],T)>r) j++;
		while(!qL.empty()&&get_dis(a[i],T)-get_dis(a[qL.front()],T)>r) qL.pop_front();
		while(!qR.empty()&&get_dis(a[i],T)-get_dis(a[qR.front()],T)>r) qR.pop_front();
		while(!qmx.empty()&&get_dis(a[i],T)-get_dis(a[qmx.front()],T)>r) qmx.pop_front();
		while(!qL.empty()&&L[a[qL.back()]]<=L[a[i]]) qL.pop_back();
		while(!qR.empty()&&R[a[qR.back()]]<=R[a[i]]) qR.pop_back();
		while(!qmx.empty()&&mx[a[qmx.back()]]<=mx[a[i]]) qmx.pop_back();
		qL.push_back(i),qR.push_back(i),qmx.push_back(i);
		if(get_dis(a[i+1],T)-get_dis(a[j],T)+1>r)
			// printf("%u %u %u\n",T,get_dis(a[i],T),get_dis(a[j],T)),
			res=min(res,max(L[a[qL.front()]]+R[a[qR.front()]],mx[a[qmx.front()]]));
	}
	// while(!qL.empty()) qL.pop_back();
	// while(!qR.empty()) qR.pop_back();
	// while(!qmx.empty()) qmx.pop_back();
	qL.init(),qR.init(),qmx.init();
	for(int i=0,j=-1;i<(int)a.size();++i){
		while(get_dis(a[i],T)-get_dis(a[j+1],T)>=r) j++;
		while(!qL.empty()&&get_dis(a[i],T)-get_dis(a[qL.front()+1],T)>=r) qL.pop_front();
		while(!qR.empty()&&get_dis(a[i],T)-get_dis(a[qR.front()+1],T)>=r) qR.pop_front();
		while(!qmx.empty()&&get_dis(a[i],T)-get_dis(a[qmx.front()+1],T)>=r) qmx.pop_front();
		if(j>=0&&get_dis(a[i],T)-get_dis(a[j],T)>=r)
			// printf("%u %u %u\n",T,get_dis(a[i],T),get_dis(a[j+1],T)),
			res=min(res,max(L[a[qL.front()]]+R[a[qR.front()]],mx[a[qmx.front()]]));
		while(!qL.empty()&&L[a[qL.back()]]<=L[a[i]]) qL.pop_back();
		while(!qR.empty()&&R[a[qR.back()]]<=R[a[i]]) qR.pop_back();
		while(!qmx.empty()&&mx[a[qmx.back()]]<=mx[a[i]]) qmx.pop_back();
		qL.push_back(i),qR.push_back(i),qmx.push_back(i);
	}
	// printf("! %u\n",T);
	// for(int i=1,j=1,k=get_nxt(i,j,T);k;k=get_nxt(i,j,T)){
	// 	printf("%u %u: ",get_dis(k,T),k&1);
	// 	printf("%u %u %u\n",L[k],R[k],mx[k]);
	// 	for(auto c=bag[k].begin();c!=bag[k].end();++c) printf("%d ",*c);
	// 	printf("\n");
	// }
	// printf("%u\n",res);
	return res;
}
int main(){
	// freopen("1.in","r",stdin);
	// freopen("1.out","w",stdout);
	cin>>r>>c>>n;
	for(int i=1;i<=n;++i) scanf("%u%u",&a[i].x,&a[i].y),X[++m]=a[i].x;
	sort(X+1,X+1+m),m=unique(X+1,X+1+m)-X-1;
	for(int i=1;i<=m;++i) mp[X[i]]=i,bag[i<<1].reserve(n),bag[i<<1|1].reserve(n);
	for(int i=1;i<=m;++i) L[i<<1]=L[i<<1|1]=R[i<<1]=R[i<<1|1]=mx[i<<1]=mx[i<<1|1]=INF;
	for(int i=1;i<=n;++i){
		INSERT(mp[a[i].x]<<1,a[i].y);
		q.push((Opt){0,0,a[i].x-1}),q.push((Opt){0,0,r-a[i].x});
		for(int j=1;j<=n;++j) q.push((Opt){0,0,a[i].x-1+r-a[j].x});
		for(int j=1;j<=n;++j) if(a[i].x