zoukankan      html  css  js  c++  java
  • 模拟赛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
    ",ans);
    }
    int main(){
    	//freopen("construct.in","r",stdin);
    	//freopen("construct.out","w",stdout);
    	Solve();
    	return 0;
    }
    
    
  • 相关阅读:
    信息安全系统设计基础学习总结第二周
    一维数组求和2
    求一维数组的最大子数组的和
    第三周学习进度
    构建之法阅读笔记二
    四则运算三
    学习进度第二周
    四则运算二
    测试第二次程序
    阅读计划
  • 原文地址:https://www.cnblogs.com/wwcdcpyscc/p/13831236.html
Copyright © 2011-2022 走看看