1. 程式人生 > 實用技巧 >[luogu p2234] [HNOI2002]營業額統計

[luogu p2234] [HNOI2002]營業額統計

傳送門

[HNOI2002]營業額統計

題目描述

Tiger最近被公司升任為營業部經理,他上任後接受公司交給的第一項任務便是統計並分析公司成立以來的營業情況。

Tiger拿出了公司的賬本,賬本上記錄了公司成立以來每天的營業額。分析營業情況是一項相當複雜的工作。由於節假日,大減價或者是其他情況的時候,營業額會出現一定的波動,當然一定的波動是能夠接受的,但是在某些時候營業額突變得很高或是很低,這就證明公司此時的經營狀況出現了問題。經濟管理學上定義了一種最小波動值來衡量這種情況:

當最小波動值越大時,就說明營業情況越不穩定。

而分析整個公司的從成立到現在營業情況是否穩定,只需要把每一天的最小波動值加起來就可以了。你的任務就是編寫一個程式幫助Tiger來計算這一個值。

第一天的最小波動值為第一天的營業額。

該天的最小波動值=min{|該天以前某一天的營業額-該天營業額|}。

輸入輸出格式

輸入格式

輸入由檔案’turnover.in’讀入。

第一行為正整數n(n<=32767) ,表示該公司從成立一直到現在的天數,接下來的n行每行有一個整數ai(|ai|<=1000000) ,表示第i天公司的營業額,可能存在負數。

輸出格式

輸入輸出樣例

輸入 #1

6
5
1
2
5
4
6

輸出 #1

12

說明/提示

結果說明:5+|1-5|+|2-1|+|5-5|+|4-5|+|6-5|=5+4+1+0+1+1=12

分析

本題我之前用一個很令人迷惑的思路寫了一個程式碼,但是樣例都過不去。怎麼除錯都除錯不出來,無奈看題解,發現了一個方法比我想的要妙很多。

思路是這樣的:

首先我們定義一個set,然後對讀入的營業額money進行如下處理:

  • 如果這是第一天的營業額,直接累計ans(ans += money),將營業額插入set。
  • 否則,在set中找到滿足大於等於money中最小的數x。(直接用lower_bound解決。由於lower_bound返回的是一個iterator,實際我們要獲取它的值需要取值,即*x)
    • 如果money == *x,那麼說明這一天最小波動值是0.此時什麼都不用幹,直接讀入下一個。
    • 如果money > *x,那麼我們再找出滿足小於money中最大的數y。由於set的有序性,實際上y就是x的前驅,直接y = x; y--;即可。然後再把這兩個值與x分別作差,取絕對值,(即abs(money - *x)和abs(money - *y)),然後再選擇最小的那個,並且ans累計(ans += min(abs(money - *x), abs(money - *y)))。最後別忘了把這個營業額插入set。

思路有了,程式碼實現應該不難,但是有一點需要注意的是,我們需要先插入一個極大值和極小值。為什麼呢?可以自己想一想。但是這個極大值和極小值不能太過極端,否則在進行作差操作時可能會爆int,導致WA70。(血淚的教訓)

叭叭叭這麼多,上程式碼辣。

程式碼

/*
 * @Author: crab-in-the-northeast 
 * @Date: 2020-07-10 08:53:08 
 * @Last Modified by: crab-in-the-northeast
 * @Last Modified time: 2020-07-10 10:02:50
 */
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <climits>
#include <set>

std :: set <int> a;

int main() {
    a.insert(INT_MAX / 4);
    a.insert(INT_MIN / 4);//不能太過極端哦

    int n, ans = 0;
    std :: cin >> n;
    for (int i = 1; i <= n; ++i) {
        int money;
        std :: cin >> money;

        if (a.size() == 2) {
            ans += money;
        } else {
            std :: set <int> :: iterator x = a.lower_bound(money);
            if (*x == money) continue;
            std :: set <int> :: iterator y = x; y--;
            ans += std :: min(std :: abs(money - *x), std :: abs(money - *y));
        }
        a.insert(money);
    }

    std :: cout << ans << std :: endl;
    return 0;
}

評測記錄

評測記錄