题目链接:http://codeforces.com/problemset/problem/1168/A
题意:给一个数组,数组中元素范围为0~n,每次你可以选择若干元素进行(ai+1)%m的操作,问使数组呈非递增的最小操作次数。
思路:因为每次都可以选若干个元素,用贪心思想,第一个元素若能超过m,则对m取模最小值为0,令其等于0就好了,假设要操作x次,每个元素加上x后,对m取模后只要不比前面小就好了,则依次判断数组的每个元素能否满足,利用二分搜索来寻找 操作数 x,x即为答案。
AC代码:
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 const int maxn = 3e5 + 5; 5 int a[maxn]; 6 int n,m; 7 8 bool check(int x) 9 { 10 int last = a[0]; 11 if(a[0] + x >= m) last = 0;//如果 a[0] 经过x次变换后大于 m 那么 a[0] 可以看做 0 。 12 for(int i = 1;i < n;i++) 13 { 14 int temp = -1;//存放a[i]与last更大的那个。 15 if(a[i] >= last) 16 { 17 temp = a[i]; 18 //如果经过x次变换后 a[i] 可以比前面大,那么temp存放前面的值就行。 19 if(a[i] + x >= m && (a[i] + x) % m >= last) 20 { 21 temp = last; 22 } 23 } 24 else if(a[i] + x >= last) temp = last; 25 if(temp == -1) return false;//找不到比前面更大的a[i]。 26 last = temp; 27 } 28 return true; 29 } 30 int main() 31 { 32 scanf("%d%d",&n,&m); 33 for(int i = 0 ;i < n;i++) 34 { 35 scanf("%d",&a[i]); 36 } 37 int l = 0,r = m + 1,ans = 0; 38 while(l <= r) 39 { 40 int mid = (l + r) >> 1; 41 if(check(mid)) r = mid - 1,ans = mid; 42 else l = mid + 1; 43 } 44 printf("%d\n",ans); 45 return 0; 46 }