Skip to main content
  1. Posts/

CodeForces-1168A Increasing by Modulo

·2 mins·

CodeForces-1168A Increasing by Modulo #

题目大意 #

给定正整数 $n, m$ 和长度为 $n$ 的数组 $a$ . 每次操作中, 你可以选择数组的一些元素, 将元素 $x$ 变为 $(x + 1)%m$ . 求让数组变为单调不减数组的最少操作次数.

Solution 1 #

如果 $k$ 次操作可行, 那么 $k + 1$ 次操作一定也可行. 基于这一点我们可以二分搜索 $k$ . 从数据范围可以看出, $check$ 函数应当在线性时间内检验 $k$ 是否满足要求, 因此我们考虑贪心, 尽可能让结尾的数字最小. 注意到 $k$ 是对整个数组操作 $k$ 次, 对于每个元素, 我们分别可以操作 $k$ 次. 如果 $a[i] > a[i - 1]$ , 假设 $a[i]$ 能在 $k$ 次操作内到达 $a[i - 1]$ , 那么就变为 $a[i - 1]$ , 否则保留 $a[i]$ ; 如果 $a[i] = a[i - 1]$ , 保留 $a[i - 1]$ ; 如果 $a[i] < a[i - 1]$ , 尽可能增加到 $a[i - 1]$ , 如果不能, 则返回 false . 基于贪心我们找到了一个 $O(n)$ 时间的检验函数, 整体复杂度 $O(nlogm)$ . 代码如下:

#include <bits/stdc++.h>
using namespace std;

int n, m;
bool check(vector<int> a, int k) {
    a[0] = ((0 + m - a[0]) % m <= k)? 0: a[0];
    for (int i = 1; i < n; i++) {
        if (a[i] > a[i - 1]) {
            a[i] = ((a[i - 1] + m - a[i]) % m <= k)? a[i - 1]: a[i];
        }
        else if (a[i] == a[i - 1]) {
            continue;
        }
        else if (a[i] < a[i - 1]) {
            if (a[i - 1] - a[i] <= k) {
                a[i] = a[i - 1];
            }
            else {
                return false;
            }
        }
    }
    return true;
}

int main() {
    cin>>n>>m;
    vector<int> a(n, 0);
    for (int i = 0; i < n; i++) {
        cin>>a[i];
    }
    int left = 0, right = m;
    while (left < right) {
        int mid = left + (right - left) / 2;
        if (check(a, mid)) {
            right = mid;
        }
        else {
            left = mid + 1;
        }
    }
    cout<<left<<endl;
    return 0;
}