题:https://codeforces.com/contest/1313/problem/C2

题意:给出n个数,分别代表第i个位置所能搭建的最大高度,问以哪一个位置的塔的高度为基准向左的每一个塔都小于等于临近右边的塔,向右每一个塔都大于等于临近的左边的塔所构建的高度之和是最大的,输出最大的高度之和;

分析:我们设一个fir[i]数组,表示当前 i 位置向左能构造的最大高度和(就想阶梯一样,i位置是阶梯的最高处),sec[i]则是向右的;

   因为求出这俩个数组后,我们直接o(n)的访问fir[i]+sec[i]-a[i]找最大的既可找出能构造出最大面积和的位置;

   对于这个fir[]的求法,对于位置 i ,可以利用前面已经算得的结果,假设位置 j (j<i)很明显的fir[i]=fir[j]+(i-j)*a[i],因为再i~j间的高度都是大于a[i]的,fir[i]是取不到fir[i~j]间的部分面积的,所以把i~j高度降为和 i 位置的高度一样即可贪心地求最大,sec[]求法类似

#include<bits/stdc++.h>
using namespace std;
const int M=5e5+;
typedef long long ll;
ll a[M],pre[M],las[M],s[M],fir[M],sec[M],ans[M];
int main(){
ios::sync_with_stdio(false);
cin.tie();
int n,top=;
cin>>n;
for(int i=;i<=n;i++)
cin>>a[i];
for(int i=;i<=n;i++){
while(top&&a[i]<a[s[top]])
top--;
pre[i]=s[top];
s[++top]=i;
fir[i]=fir[pre[i]]+1ll*(i-pre[i])*a[i];
}
s[top=]=n+;
for(int i=n;i>=;i--){
while(top&&a[i]<a[s[top]])
top--;
las[i]=s[top];
s[++top]=i;
sec[i]=sec[las[i]]+1ll*(las[i]-i)*a[i];
}
int pos=;
for(int i=;i<=n;i++){
if(fir[i]+sec[i]-a[i]>fir[pos]+sec[pos]-a[pos])
pos=i;
}
for(int i=pos;i;i=pre[i])
for(int j=i;j>pre[i];j--)
ans[j]=a[i];
for(int i=pos;i;i=las[i])
for(int j=i;j<las[i];j++)
ans[j]=a[i];
for(int i=;i<=n;i++)
cout<<ans[i]<<' ';
return ;
}

分治做法:

分析:对于任意一段[l,r]的高度限制,假设a[i]是其中最小的高度,那么 要么是 i 的右边的高度全设为a[i],要么 i 的左边的高度全设为a[i]这俩种可能,那我们就分治下这些区间就行了;

   找最小的高度用线段树实现即可,也可用其他方法;

   复杂度分析,退化的情况我们分治的区间是[1,n],[1,n-1],[1,n-2]。。。这样n个区间,那么只要我们保证每个区间只是log级别的复杂度即可;

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define lson root<<1,l,midd
#define rson root<<1|1,midd+1,r
typedef long long ll;
const int inf=0x3f3f3f3f;
const int M=5e5+;
int n;
struct node{
ll val,id;
}tr[M<<];
ll a[M],ans[M];
void up(int root){
if(tr[root<<].val<=tr[root<<|].val){
tr[root]=tr[root<<];
}
else
tr[root]=tr[root<<|];
}
void build(int root,int l,int r){
if(l==r){
tr[root].val=a[l];
tr[root].id=l;
return ;
}
int midd=(l+r)>>;
build(lson);
build(rson);
up(root);
}
node query(int L,int R,int root,int l,int r){
if(L<=l&&r<=R){
return tr[root];
}
node res;
res.val=1e9+;
int midd=(l+r)>>;
if(L<=midd){
node now=query(L,R,lson);
if(now.val<res.val)
res=now;
}
if(R>midd){
node now=query(L,R,rson);
if(now.val<res.val)
res=now;
}
return res;
}
ll solve(int l,int r){
// cout<<l<<"!!"<<r<<endl;
if(l>r)
return 0ll;
if(l==r){
ans[l]=a[l];
return a[l];
}
node now=query(l,r,,,n);
// cout<<now.id<<"!!"<<endl;
ll lsum=solve(l,now.id-);
ll rsum=solve(now.id+,r);
if(lsum+now.val+1ll*now.val*(r-now.id)>1ll*now.val*(now.id-l)+now.val+rsum){
for(int i=now.id;i<=r;i++)
ans[i]=now.val;
return lsum+now.val+now.val*(r-now.id);
}
else{
for(int i=l;i<=now.id;i++)
ans[i]=now.val;
return now.val*(now.id-l)+now.val+rsum;
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie();
cin>>n;
for(int i=;i<=*n;i++)
tr[i].val=inf;
for(int i=;i<=n;i++)
cin>>a[i];
build(,,n); solve(,n);
for(int i=;i<=n;i++)
cout<<ans[i]<<' ';
return ;
}

Codeforces Round #622 (Div. 2)C2 Skyscrapers最大"尖"性矩形,思维||分治的更多相关文章

  1. Codeforces Round #622 (Div. 2) C2. Skyscrapers (hard version)(单调栈,递推)

    Codeforces Round #622 (Div. 2) C2. Skyscrapers (hard version) 题意: 你是一名建筑工程师,现给出 n 幢建筑的预计建设高度,你想建成峰状, ...

  2. Codeforces Round #622 (Div. 2).C2 - Skyscrapers (hard version)

    第二次写题解,请多多指教! http://codeforces.com/contest/1313/problem/C2 题目链接 不同于简单版本的暴力法,这个数据范围扩充到了五十万.所以考虑用单调栈的 ...

  3. Codeforces Round #622 (Div. 2) C2 - Skyscrapers (hard version) 单调栈

    从左往右扫,找到比第i个小的第一个数字,l[i] = l[last] + (i - last) * m[i],用单调栈O(n)维护这个过程,再从右往左扫,同理可以算出r数组,注意一下long long ...

  4. Codeforces Round #622(Div 2) C1. Skyscrapers (easy version)

    题目链接: C1. Skyscrapers (easy version) 题目描述: 有一行数,使得整个序列满足 先递增在递减(或者只递增,或者只递减) ,每个位置上的数可以改变,但是最大不能超过原来 ...

  5. Codeforces Round #622 (Div. 2) C1. Skyscrapers (easy version)(简单版本暴力)

    This is an easier version of the problem. In this version n≤1000n≤1000 The outskirts of the capital ...

  6. Codeforces Round #622 (Div. 2)C2

    题意 N长度为500000以内,一个数字两边的数字不能都比他高,最多高一边 求他最大sum.叙述有问题,直接看样例 3 10 6 8 因为6左右都比他高,选择10 6 6或者6 6  8,sum明显前 ...

  7. Codeforces Round #622 (Div. 2) B. Different Rules(数学)

    Codeforces Round #622 (Div. 2) B. Different Rules 题意: 你在参加一个比赛,最终按两场分赛的排名之和排名,每场分赛中不存在名次并列,给出参赛人数 n ...

  8. Codeforces Round #622 (Div. 2) A. Fast Food Restaurant(全排列,DFS)

    Codeforces Round #622 (Div. 2) A. Fast Food Restaurant 题意: 你是餐馆老板,虽然只会做三道菜,上菜时还有个怪癖:一位客人至少上一道菜,且一种菜最 ...

  9. Codeforces Round #529 (Div. 3) E. Almost Regular Bracket Sequence (思维)

    Codeforces Round #529 (Div. 3) 题目传送门 题意: 给你由左右括号组成的字符串,问你有多少处括号翻转过来是合法的序列 思路: 这么考虑: 如果是左括号 1)整个序列左括号 ...

随机推荐

  1. 吴裕雄--天生自然java开发常用类库学习笔记:取得当前日期

    import java.util.* ; // 导入需要的工具包 class DateTime{ // 以后直接通过此类就可以取得日期时间 private Calendar calendar = nu ...

  2. nginx location语法解释

    1.没有修饰符 表示:必须以指定模式开始,如:              默认模式 server { server_name baidu.com; location /abc { …… } } htt ...

  3. cf 763B. Timofey and rectangles

    %%题解,脑洞好大啊. 四色定理什么鬼的..所以一定是yes. 因为矩形边长都是奇数,所以可以按左下角分类,一共4类,分别1,2,3,4就可以了. (需要4种颜色的情况大概就是4个矩形围起来一个矩形) ...

  4. 3分钟教你用python制作一个简单词云

    首先需要安装三个包: # 安装:pip install matplotlib # 安装:pip install jieba # 安装pip install wordcloud 1.制作英文字母的词云 ...

  5. 168-PHP 输出系统当前时间

    <body style="font-family:'华文彩云'; color:#0000CC; font-size:20px"> 系统的当前时间是: <?php ...

  6. 留学Essay写作:从入门到精通

    Essay作为最常见的英国大学作业形式,几乎是每个留学生都绕不过去的任务. 大部分人提到自己在英国的大学生活,都会回想起无数个“血泪交加”的夜晚,从白天到傍晚再到深夜,点灯熬油的查资料,写essay. ...

  7. 十四、 React路由(react-router4.x): 动态路由、get传值、React中使用url模块

    概述 新闻列表 -跳转-> 详情页 时,想把列表对应的id传到详情页里,可用到三种传值方法: 1.动态路由传值 2.get传值 3.localstorage传值 一.动态路由传值 [App.js ...

  8. main:处理命令行选项

    #include<iostream> #include<stdlib.h> using namespace std; int main(int argc, char** arg ...

  9. selenium2Library无法启动chrome

    使用其他浏览器都没有影响,唯独chrome启动不起来,去掉IE-连接-局域网设置-自动检测设置就OK了

  10. LeetCode刷题(持续更新ing……)

    准备刷题了!已经预见未来的日子是苦并快乐的了!虽然 N 年前刷过题,但现在感觉数据结构与算法的基本功快忘光了