题解 - 次大值求和(sum)

题目描述

在绍兴市编程达人的聚会中,厌倦了求最大值的新昌小伙伴想出了一个求次大值的方案,想来考考大家。
给定一个 1 到 n 的数字各出现一次的排列 a[1]、a[2]、…、a[n],定义 f(l,r)表示 a[l]、a[l+1]、a[l+2]、…、a[r]中的次大值,你需要求出对于所有的 1<=i<j<=n,f(i,j)的和。

输入

第一行一个整数 n,第二行 n 个整数表示 a[i]。

输出

一行一个整数,表示答案。

样例

样例输入

3
2 3 1

样例输出

5

提示

样例输入2:
8
8 2 7 3 4 5 6 1
样例输出2:
136
【样例解释】
样例 1:区间[1,2]和[1,3]的次大值是 2,区间[2,3]的次大值是 1,求和后的结果 为 5。
【数据范围约定】
对于 30%的数据,n<=100;
对于 70%的数据,n<=5000;
对于 100%的数据,n<=100000。

分析

对于某个数x,考虑其作为次大值的区间

找出每个数左边第一个和第二个比它大的,右边同理,区间数即为 d1 * d3 + d2 * d4

实现

双链表指示左右的大小关系,从小到大排序,枚举,求出贡献后将当前点删除。

    for(int i = 1;i <= n;i++) l[i] = i - 1,r[i] = i + 1;
    r[n + 1] = n + 1;
 
    for(int i = 1;i <= n;i++){
        int idx = a[i].second;
        
		// 对应操作
		
        r[l[idx]] = r[idx];
        l[r[idx]] = l[idx];
    }

代码

#include<bits/stdc++.h>
 
using namespace std;
 
typedef long long LL;
typedef pair<int,int> PII;
 
const int N = 100000 + 10;
 
int n;
PII a[N];
int l[N],r[N];
LL res;
 
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
 
    cin >> n;
    for(int i = 1;i <= n;i++){
        cin >> a[i].first;
        a[i].second = i;
    }
 
    sort(a + 1,a + 1 + n);
 
    for(int i = 1;i <= n;i++) l[i] = i - 1,r[i] = i + 1;
    r[n + 1] = n + 1;
 
    for(int i = 1;i <= n;i++){
        int idx = a[i].second;
 
        int l1,l2,r1,r2;
        l1 = l[idx],l2 = l[l1],r1 = r[idx],r2 = r[r1];
 
        res += (LL)i * ((l1 - l2) * (r1 - idx) + (r2 - r1) * (idx - l1));
 
        r[l[idx]] = r[idx];
        l[r[idx]] = l[idx];
    }
 
    cout << res;
 
    return 0;
}
  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值