题目:减成一
来源:“科林明伦杯”哈尔滨理工大学第十届程序设计竞赛(同步赛)

解题思路

题目:存在 n 个数,每次操作可以任选一个区间使得区间内的所有数字减一。问最少多少次操作,可以让所有数都变成 1。

① 以 1 所在的位置作为区间的边界,但不包括该位置。
② 遍历区间得到区间的最小值 mini,将区间中的每个数减去 mini - 1,并将该值计入结果 ans
③ 此时,原来区间最小值所在位置的数字变成 1,继续步骤①,直至所有数都变成 1。

C++代码

#include<iostream>
#include<vector>
using namespace std;

int ans;

void opCnt(vector<int>& arr, int left, int right){
    if(left > right)
        return;
    if(left == right){
        ans += arr[left] - 1;
        return;
    }
    vector<int> v;
    v.push_back(left);
    int mini = arr[left];
    for(int i=left+1; i<=right; ++i){
        if(arr[i] < mini){
            v.clear();
            v.push_back(i);
            mini = arr[i];
        }
        else if(arr[i] == mini){
            v.push_back(i);
        }
    }

    int minus = mini - 1;
    ans += minus;
    for(int i=left; i<=right; ++i){
        arr[i] -= minus;
    }
    opCnt(arr, left, v[0]-1);
    for(int i=0; i<v.size()-1; ++i){
        opCnt(arr, v[i]+1, v[i+1]-1);
    }
    opCnt(arr, v.back()+1, right);
}

int main(){
    int t;
    cin >> t;
    while(t){
        int n;
        cin >> n;
        vector<int> arr(n);
        for(int i=0; i<n; ++i)
            cin >> arr[i];
        ans = 0;
        opCnt(arr, 0, n-1);
        cout << ans << endl;
        --t;
    }
    return 0;
}