模拟赛18 T1 施工 题解

前言:

真的是不容易啊。这个题在考场上想到了最关键的性质,但是没写出来。
后来写出来,一直调,小错不断。
没想到改的最后一个错误是两个int 乘起来爆了int
其实最后我还是觉得复杂度很假。\(n^2\) 过百万。
此处对拍使用了DeepinC的代码,计算正确答案使用了硕队和张大仙的代码,感谢。
不过我感觉写的太罗嗦了,200行。

解析:

容易发现,每个建筑长高,当且仅当它左右都比它高。于是考场上我扫了一边,拿到了0分的好成绩。
因为如果这样想的话,一个建筑是可以长高多次的。假如有一个序列 \(a_1>a_2>a_3<a_4<a_5\)
那么\(a_3\)可能会长高到和旁边的\(a_2,a_4\)一样高,然后,\(a_2,a_3,a_4\)再同时长到和\(a_1,a_5\)一样高。
所以我们考虑用队列维护一下,队列中维护每个建筑(或高度相同且连续的建筑块)。每次尝试让它长高。
二次函数解析式真的挺恶心,算对称轴的时候还要扫一边这个建筑块统治的区间。(这也是我觉得复杂度很假的原因)
而且因为在左右两边的建筑,函数解析式和在中间的不一样,所以貌似需要分类讨论一下。。。
代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1000000+10,Inf=1e9+7;
int a[maxn],b[maxn];
int n,c,head,tail;
ll ans;
struct node{
	int l,r,val;
	node(){}
	node(int x,int y,int z){
		l=x;
		r=y;
		val=z;
	}
};
queue <node> q;
void get_ans(){
	for(int i=1;i<=n;++i){
		int t=b[i]-a[i];
		ans+=1ll*t*t;
	}
	for(int i=2;i<=n;++i) ans+=1ll*c*abs(b[i]-b[i-1]);
}
void Merge(){
	ll d,e,t1,t2,res1,res2,f,g;
	while(!q.empty()){
		node t=q.front();
		q.pop();
		if(t.l==0&&t.r==n+1) break;
		if(!(t.val<b[t.l]&&t.val<b[t.r])) continue;
		if(t.l==0){
			e=b[t.r]-t.val;
			d=t.r-t.l-1;
			t1=c;
			for(int i=t.l+1;i<t.r;++i) t1-=2*(b[i]-a[i]); 
			t1/=(d*2);
			t2=t1+1;
			t1=max(0ll,min(e,t1));
			t2=max(0ll,min(e,t2));
			res1=-t1*c+e*c;
			for(int i=t.l+1;i<t.r;++i){
				ll sss1=t1+b[i]-a[i];
				res1+=sss1*sss1;
			}
			res2=-t2*c+e*c;
			for(int i=t.l+1;i<t.r;++i){
				ll sss2=t2+b[i]-a[i];
				res2+=sss2*sss2;
			}
			if(res1>res2) swap(t1,t2);
			for(int i=t.l+1;i<t.r;++i) b[i]+=t1;
			if(t1==e){
				tail=t.r;
				while(b[tail]==t.val+t1) tail++;
				q.push(node(0,tail,t.val+t1));
			}
		}else if(t.r==n+1){
			e=b[t.l]-t.val;
			d=t.r-t.l-1;
			t1=c;
			for(int i=t.l+1;i<t.r;++i) t1-=2*(b[i]-a[i]); 
			t1/=(d*2);
			t2=t1+1;
			t1=max(0ll,min(e,t1));
			t2=max(0ll,min(e,t2));
			res1=-t1*c+e*c;
			for(int i=t.l+1;i<t.r;++i){
				ll sss1=t1+b[i]-a[i];
				res1+=sss1*sss1;
			}
			res2=-t2*c+e*c;
			for(int i=t.l+1;i<t.r;++i){
				ll sss2=t2+b[i]-a[i];
				res2+=sss2*sss2;
			}
			if(res1>res2) swap(t1,t2);
			for(int i=t.l+1;i<t.r;++i) b[i]+=t1;
			if(t1==e){
				head=t.l;
				while(b[head]==t.val+t1) head--;
				q.push(node(head,n+1,t.val+t1));
			}
		}else{
			if(b[t.l]<b[t.r]){
				e=b[t.l]-t.val;
				f=b[t.l]+b[t.r]-t.val*2;
				d=t.r-t.l-1;
				t1=c;
				for(int i=t.l+1;i<t.r;++i) t1-=b[i]-a[i];
				t1/=d;
				t2=t1+1;
				t1=max(0ll,min(e,t1));
				t2=max(0ll,min(e,t2));
				res1=-2*t1*c+f*c;
				res2=-2*t2*c+f*c;
				for(int i=t.l+1;i<t.r;++i){
					ll sss1=t1+b[i]-a[i];
					res1+=sss1*sss1;
				}
				for(int i=t.l+1;i<t.r;++i){
					ll sss2=t2+b[i]-a[i];
					res2+=sss2*sss2;
				}
				if(res1>res2) swap(t1,t2);
				for(int i=t.l+1;i<t.r;++i) b[i]+=t1;
				if(t1==e){
					head=t.l;
					while(b[head]==t.val+t1) head--;
					q.push(node(head,t.r,t.val+t1));
				}
			}else if(b[t.l]==b[t.r]){
				e=b[t.l]-t.val;
				f=b[t.l]+b[t.r]-t.val*2;
				d=t.r-t.l-1;
				t1=c;
				for(int i=t.l+1;i<t.r;++i) t1-=b[i]-a[i];
				t1/=d;
				t2=t1+1;
				t1=max(0ll,min(e,t1));
				t2=max(0ll,min(e,t2));
				res1=-2*t1*c+f*c;
				res2=-2*t2*c+f*c;
				for(int i=t.l+1;i<t.r;++i){
					ll sss1=t1+b[i]-a[i];
					res1+=sss1*sss1;
				}
				for(int i=t.l+1;i<t.r;++i){
					ll sss2=t2+b[i]-a[i];
					res2+=sss2*sss2;
				}
				if(res1>res2) swap(t1,t2);
				for(int i=t.l+1;i<t.r;++i) b[i]+=t1;
				if(t1==e){
					head=t.l;
					tail=t.r;
					while(b[head]==t.val+t1) head--;
					while(b[tail]==t.val+t1) tail++;
					q.push(node(head,tail,t.val+t1));
				}
			}else{
				e=b[t.r]-t.val;
				d=t.r-t.l-1;
				f=b[t.l]+b[t.r]-t.val*2;
				t1=c;
				for(int i=t.l+1;i<t.r;++i) t1-=b[i]-a[i];
				t1/=d;
				t2=t1+1;
				t1=max(0ll,min(e,t1));
				t2=max(0ll,min(e,t2));
				res1=-2*t1*c+f*c;
				res2=-2*t2*c+f*c;
				for(int i=t.l+1;i<t.r;++i){
					ll sss1=t1+b[i]-a[i];
					res1+=sss1*sss1;
				}
				for(int i=t.l+1;i<t.r;++i){
					ll sss2=t2+b[i]-a[i];
					res2+=sss2*sss2;
				}
				if(res1>res2) swap(t1,t2);
				for(int i=t.l+1;i<t.r;++i) b[i]+=t1;
				if(t1==e){
					tail=t.r;
					while(b[tail]==t.val+t1) tail++;
					q.push(node(t.l,tail,t.val+t1));
				}
			}
		}	
	}
}
void Solve(){
	scanf("%d%d",&n,&c);
	for(int i=1;i<=n;++i) scanf("%d",&b[i]);
	b[0]=Inf;
	b[n+1]=Inf;
	int i=1;
	while(i<=n){
		int l=i-1;
		int r=i+1;
		while(b[r]==b[i]) r++;
		q.push(node(l,r,b[i]));
		i=r;
	}
	memcpy(a,b,sizeof(b));
	a[0]=Inf;
	a[n+1]=Inf;
	Merge();
	get_ans();
	printf("%lld\n",ans);
}
int main(){
	//freopen("construct.in","r",stdin);
	//freopen("construct.out","w",stdout);
	Solve();
	return 0;
}

posted @ 2020-10-17 14:50  “起个名字真难♘”  阅读(97)  评论(2编辑  收藏  举报