Codeforces Round #622 Skyscrapers (hard version)

36 篇文章 0 订阅
20 篇文章 0 订阅

题意:

给你 n n n个数 m i m_i mi,要求找一个序列 a i a_i ai满足 a i < = m i a_i<=m_i ai<=mi并且 a i a_i ai左右不能同时有 a j > a i ( j ! = i ) a_j>a_i(j!=i) aj>aij!=i
求这个序列和最大的情况。

思路:

首先 a i a_i ai左右不能同时有 a j > a i ( j ! = i ) a_j>a_i(j!=i) aj>ai(j!=i),这个形状就是开口向上的二次函数。
那么与他相反的必然就是开口向下的二次函数或者(其左(右)的一部分),因为左右不能同时大于 a i a_i ai
那么就有3种可能:
①左右同时小于等于它
②左大右小
③左小右大

这个就是开口向下的二次函数或者(其左(右)的一部分)这种。

那么暴力做法就是枚举顶点,让其左右2边的都满足下降,同时维护一个最小值,
取每个顶点的最大值即可。

那么优化的话,我们每次枚举顶点,看能不能利用前面的已经求出来的东西,要让其下降,我们找到左边(右)第一个比它小的位置id,然后这个顶点i的答案就是ans[id] + (i-id)*a[i],而得到左边第一个比它小的,可以用单调栈维护,维护一个单调递减栈,因为左(右)边大于当前a[i]的值肯定用不上了,因为如果后面一个数比a[i]大,那么a[i]就是后面一个数的第一个,如果比a[i]小,那么大于它的肯定没用了,维护一个单调递减的栈就好了,同时从后面扫一遍,然后答案就是 m a x ( p r e [ i ] + h e d [ i ] − a [ i ] ) max(pre[i] + hed[i] - a[i]) max(pre[i]+hed[i]a[i])因为a[i]多算了一次。

code(easy)

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int man = 2e5+10;
#define IOS ios::sync_with_stdio(0)
template <typename T>
inline T read(){T sum=0,fl=1;int ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')fl=-1;
for(;isdigit(ch);ch=getchar())sum=sum*10+ch-'0';
return sum*fl;}
template <typename T>
inline void write(T x) {static int sta[35];int top=0;
do{sta[top++]= x % 10, x /= 10;}while(x);
while (top) putchar(sta[--top] + 48);}
template<typename T>T gcd(T a, T b) {return b==0?a:gcd(b, a%b);}
template<typename T>T exgcd(T a,T b,T &g,T &x,T &y){if(!b){g = a,x = 1,y = 0;}
else {exgcd(b,a%b,g,y,x);y -= x*(a/b);}}
#ifndef ONLINE_JUDGE
#define debug(fmt, ...) {printf("debug ");printf(fmt,##__VA_ARGS__);puts("");}
#else
#define debug(fmt, ...)
#endif
typedef long long ll;
const ll mod = 1e9+7;
int a[man];
int res[man],tp[man];

int main() {
    #ifndef ONLINE_JUDGE
        //freopen("in.txt", "r", stdin);
        //freopen("out.txt","w",stdout);
    #endif
    int n;
    scanf("%d",&n);
    for(int i = 1;i <= n;i++){
        scanf("%d",&a[i]);
    }
    ll ans = 0;
    for(int i = 1;i <= n;i++){
        ll sum = a[i];
        int minn = a[i];
        tp[i] = a[i];
        for(int j = i-1;j >= 1;j--){
            minn = min(minn,a[j]);
            tp[j] = minn;
            sum += minn;
        }
        minn = a[i];
        for(int j = i+1;j <= n;j++){
            minn = min(minn,a[j]);
            tp[j] = minn;
            sum += minn;
        }
        if(sum>ans){
            ans = sum;
            for(int j = 1;j <= n;j++){
                res[j] = tp[j];
            }
        }
    }
    for(int i = 1;i <= n;i++){
        printf(i==n?"%d\n":"%d ",res[i]);
    }
    return 0;
}

code(hard)

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int man = 5e5+10;
#define IOS ios::sync_with_stdio(0)
template <typename T>
inline T read(){T sum=0,fl=1;int ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')fl=-1;
for(;isdigit(ch);ch=getchar())sum=sum*10+ch-'0';
return sum*fl;}
template <typename T>
inline void write(T x) {static int sta[35];int top=0;
do{sta[top++]= x % 10, x /= 10;}while(x);
while (top) putchar(sta[--top] + 48);}
template<typename T>T gcd(T a, T b) {return b==0?a:gcd(b, a%b);}
template<typename T>T exgcd(T a,T b,T &g,T &x,T &y){if(!b){g = a,x = 1,y = 0;}
else {exgcd(b,a%b,g,y,x);y -= x*(a/b);}}
#ifndef ONLINE_JUDGE
#define debug(fmt, ...) {printf("debug ");printf(fmt,##__VA_ARGS__);puts("");}
#else
#define debug(fmt, ...)
#endif
typedef long long ll;
const ll mod = 1e9+7;
int a[man];
int res[man],sta[man];
ll pre[man],hed[man];

int main() {
    #ifndef ONLINE_JUDGE
        //freopen("in.txt", "r", stdin);
        //freopen("out.txt","w",stdout);
    #endif
    int n;
    scanf("%d",&n);
    for(int i = 1;i <= n;i++)scanf("%d",&a[i]);
    int top = 0;
    pre[0] = 0;
    for(int i = 1;i <= n;i++){
        while(top&&a[sta[top]]>=a[i])top--;
        if(!top)pre[i] = 1ll*i*a[i];
        else pre[i] = 1ll*(i-sta[top])*a[i] + pre[sta[top]];
        sta[++top] = i;
    }
    top = 0;
    hed[n+1] = 0;
    for(int i = n;i >= 1;i--){
        while(top&&a[sta[top]]>=a[i])top--;
        if(!top)hed[i] = 1ll*(n-i+1)*a[i];  
        else hed[i] = 1ll*(sta[top]-i)*a[i] + hed[sta[top]];
        //cout << i << " " << hed[i] << endl;
        sta[++top] = i;
    }
    ll ans = 0,ans_id = 0;
    for(int i = 1;i <= n;i++){
        ll tp = pre[i]+hed[i]-a[i];
        if(tp>ans){
            ans = tp;
            ans_id = i; 
        }
    }
    int minn = a[ans_id];
    res[ans_id] = minn;
    for(int i = ans_id-1;i >= 1;i--){
        minn = min(minn,a[i]);
        res[i] = minn;
    }
    minn = a[ans_id];
    for(int i = ans_id+1;i <= n;i++){
        minn = min(minn,a[i]);
        res[i] = minn;
    }
    for(int i = 1;i <= n;i++){
        printf(i==n?"%d\n":"%d ",res[i]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值