Toad Zitz has an array of integers, each integer is between 0 and m−1 inclusive. The integers are a1,a2,…,an.
In one operation Zitz can choose an integer k and k indices i1,i2,…,ik such that 1≤i1<i2<…<ik≤n. He should then change aij to ((aij+1)modm) for each chosen integer ij. The integer m is fixed for all operations and indices.
Here xmody denotes the remainder of the division of x by y.
Zitz wants to make his array non-decreasing with the minimum number of such operations. Find this minimum number of operations.
Input
The first line contains two integers n and m (1≤n,m≤300000) — the number of integers in the array and the parameter m.
The next line contains n space-separated integers a1,a2,…,an (0≤ai<m) — the given array.
Output
Output one integer: the minimum number of described operations Zitz needs to make his array non-decreasing. If no operations required, print 0.
It is easy to see that with enough operations Zitz can always make his array non-decreasing.
Sample:
Input:
5 3
0 0 0 1 2
OutPut:
0
Input:
5 7
0 6 1 3 2
OutPut:
1
Note
In the first example, the array is already non-decreasing, so the answer is 0.
In the second example, you can choose k=2, i1=2, i2=5, the array becomes [0,0,1,3,3]. It is non-decreasing, so the answer is 1.
题目大意:
给定一个序列,每次可以操作数组中任意多个数字,每次操作可以使当前位置的数字 arr[i] 变成 (arr[i]+1)%m,求至少多少次操作可以使序列变成一个非递减的序列(不严格的单调递增)。
思路
对每个数字操作 m 次和没操作一样,所以每个数最多操作 m-1 次。可以二分每个数的操作次数,如果当前操作次数为 mid ,如果对该数字操作 0 次到 mid 次没有任何一次符合条件,说明该数字操作 mid 次不能满足条件,二分的区间应该将小的一部分舍去,以此类推,如果满足条件,说明在当前的区间内,某一个数满足的条件,仅有一个数字满足条件是不行的,所以还要枚举数组中的每一个数字,如果全部满足条件,就能将二分区间缩小,舍去大的部分。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#ifdef ONPC
mt19937 rnd(228);
#else
mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count());
#endif
int main() {
#ifdef ONPC
freopen("a.in", "r", stdin);
#endif
ios::sync_with_stdio(0);
cin.tie(0);
int n, m;
cin >> n >> m;
vector <int> a(n);
for (int &x : a) {
cin >> x;
}
int l = -1, r = m;
while (l < r - 1) {
int mid = (l + r) / 2;
int prev = 0;
//prev 代表的前一个位置的数字
bool bad = false;
//bad 判断能否满足条件
for (int i = 0; i < n; i++) {
int lf = a[i], rf = a[i] + mid;
if ((lf <= prev && prev <= rf) || (lf <= prev + m && prev + m <= rf)) {
continue;
//如果通过mid次操作能让前面的点小于等于后面的点,说明可行
}
if (lf < prev) {
//从上面的循环出来,不满足上述条件并且 lf < prev 说明 prev > rf
//即 mid 次操作不能让前面的点小于等于后面的点,此操作次数不可行
// mid 次不行,比 mid 小更不行
bad = true;
break;
}
else {
//如果 prev <= lf ,也就是说出现了一个比 prev 更小的值
//这时为了保证操作尽可能少,可以直接不操作,让 prev = lf
prev = lf;
}
}
if (bad) {
l = mid;
}
else {
r = mid;
}
}
cout << r << '\n';
return 0;
}