51Nod 2070 最小罰款 簡單題

1. 題目描述

1.1. Limit

Time Limit: 1000 ms

Memory Limit: 131072 kB

1.2. Problem Description

小偉報名參加中央電視臺的智力大沖浪節目。本次挑戰賽吸引了衆多參賽者,主持人爲了表彰大家的勇氣,先獎勵每個參賽者mm元。先不要太高興!因爲這些錢還不一定都是你的?!接下來主持人宣佈了比賽規則:

首先,比賽時間分爲nn個時段(n500)(n≤500),它又給出了很多小遊戲,每個小遊戲都必須在規定期限tit_i前完成(1tin)(1 \le t_i \le n)。如果一個遊戲沒能在規定期限前完成,則要從獎勵費mm元中扣去一部分錢wiw_iwiw_i爲自然數,不同的遊戲扣去的錢是不一樣的。現在你要設計方法,使得你能得到最多的獎勵。


1.3. Input

輸入共 4 行
第 1 行爲 mm ,表示一開始獎勵給每位參賽者的錢;
第 2 行爲 nn,表示有 nn 個小遊戲;
第 3 行有 nn 個數,分別表示遊戲 1 到 nn 的規定完成期限;
第 4 行有 nn 個數,分別表示遊戲 1 到 nn 不能在規定期限前完成的扣款數。


1.4. Output

輸出文件僅 1 行。表示小偉能贏取最多的錢。


1.5. Sample Input

10000
7
4 2 4 3 1 4 6
70 60 50 40 30 20 10

1.6. Sample Output

9950

1.7. Source

51Nod 2070 最小罰款


2. 解讀

若存在規定完成期限 tit_i相同的任務,則可能會出現懲罰。

若有數字tet_e,滿足1te<max(ti)1 \le t_e < \max(t_i) 且在所有任務的完成期限中沒有出現,那麼 對完成期限 ti>tet_i > t_e 的任務 txt_x,即使出現了一次重複,也可以使用 tet_e 這個時間來完成。

若任務 txt_x 的截止時間 tit_i 前不存在沒有出現的數字tet_e,或 tet_etit_i 之前出現的重複任務消耗掉了,那麼懲罰出現。

懲罰的最優選擇方案爲,將所有任務按照懲罰金額wiw_i從小到大排序,選擇第一個符合截止時間 titxt_i \le t_x 條件的任務接受懲罰。即將現有金額 mm 減去 wiw_i

對所有規定完成期限 tit_i相同的任務進行處理以後,即可求得答案。

3. 代碼

#include <iostream>
#include <map>
#include <math.h>
#include <string.h>
using namespace std;

// 記錄最晚完成時間
long long timeList[500];
// 記錄懲罰
long long penalty[500];
// 記錄出現次數
long long countTime[500];
// 時間到懲罰的映射
multimap<long long, long long> timeToPenalty;
// map指針
multimap<long long, long long>::iterator iter;
// 將前面輪空的time次數存儲起來
long long storage;

int main()
{
    long long m, n, maxTime;
    // 讀入m
    scanf("%lld", &m);
    // 讀入n
    scanf("%lld", &n);
    // 初始化數組
    memset(timeList, 0, sizeof(timeList));
    memset(penalty, 0, sizeof(penalty));
    memset(countTime, 0, sizeof(countTime));
    // 初始化最大值
    maxTime = 0;
    // 初始化存儲
    storage = 0;
    // 存儲時間
    for (long long i = 0; i < n; i++) {
        // 讀入時間
        scanf("%lld", &timeList[i]);
        // 存儲時間的出現次數
        countTime[timeList[i]]++;
        // max
        maxTime = max(maxTime, timeList[i]);
    }
    // 存儲懲罰
    for (long long i = 0; i < n; i++) {
        // 讀入懲罰
        scanf("%lld", &penalty[i]);
        // 存入map
        timeToPenalty.insert(make_pair(penalty[i], timeList[i]));
    }
    // 判斷是否有重複元素
    for (long long i = 1; i <= maxTime; i++) {
        // 先消耗存儲
        if (countTime[i] > 1 && storage > 0) {
            int countMark = countTime[i] - 1;
            for (int j = 0; j < countMark; j++) {
                countTime[i]--;
                storage--;
                if (storage <= 0) {
                    break;
                }
            }
        }
        // 若有重複時間
        if (countTime[i] > 1) {
            // 將penalty從小到大進行遍歷
            for (iter = timeToPenalty.begin(); iter != timeToPenalty.end(); iter++) {
                // 若符合條件
                if (iter->second <= i && iter->second != -1) {
                    // 減去penalty
                    m -= iter->first;

                    // 將已經減去的penalty清除
                    iter->second = -1;
                    // countTime-1
                    countTime[i]--;
                    if (countTime[i] <= 1) {
                        // 退出循環
                        break;
                    }
                }
            }
        } else if (countTime[i] == 0) {
            // 若有time輪空,存儲起來
            storage++;
        }
    }
    // 輸出
    printf("%lld", m);
}

聯繫郵箱:[email protected]

Github:https://github.com/CurrenWong

歡迎轉載/Star/Fork,有問題歡迎通過郵箱交流。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章