1. 程式人生 > 其它 >CodeForces -1168A Increasing by Modulo(二分答案)

CodeForces -1168A Increasing by Modulo(二分答案)

技術標籤:二分

題目連結:點選這裡

題目大意:
給出 n , m n,m n,m 和一個長度為 n n n 的序列 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an
每次操作可以選擇一個數 k k k k k k 個數 b 1 , b 2 , . . . , b k b_1,b_2,...,b_k b1,b2,...,bk ,使得 a b i = ( a b i + 1 ) m o d    m a_{b_i}=(a_{b_i}+1) \mod m abi=(abi+1)modm ,求使序列 a a

a 單調不下降的最小操作次數

題目分析:
最小操作次數顯然滿足答案的單調性,我們考慮二分答案的 c h e c k check check 如何寫:我們對相鄰元素 a [ i ] , a [ i − 1 ] a[i],a[i-1] a[i],a[i1] 的大小關係分三種情況討論:

  1. a [ i ] = a [ i − 1 ] a[i]=a[i-1] a[i]=a[i1] 此時讓 a [ i ] a[i] a[i] 保持不變即可
  2. a [ i ] > a [ i − 1 ] a[i]>a[i-1] a[i]>a[i1] 如果能讓 a [ i ] a[i] a[i] 通過迴圈變成 a [ i − 1 ] a[i-1]
    a[i1]
    更好,此時需要操作次數為 a [ i − 1 ] + m − a [ i ] a[i-1]+m-a[i] a[i1]+ma[i] ,如果操作次數不夠就維持原樣即可
  3. a [ i ] < a [ i − 1 ] a[i]<a[i-1] a[i]<a[i1] 此時我們需要讓 a [ i ] a[i] a[i] 增加到 a [ i − 1 ] a[i-1] a[i1] 使之保持序列的單調不下降,需要的操作次數為 a [ i − 1 ] − a [ i ] a[i-1]-a[i] a[i1]a[i]

具體細節見程式碼:

#include<iostream>
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<vector> #include<set> #include<map> #define ll long long #define inf 0x3f3f3f3f using namespace std; ll read() { ll res = 0,flag = 1; char ch = getchar(); while(ch<'0' || ch>'9') { if(ch == '-') flag = -1; ch = getchar(); } while(ch>='0' && ch<='9') { res = (res<<3)+(res<<1)+(ch^48);//res*10+ch-'0'; ch = getchar(); } return res*flag; } const int maxn = 5e5+5; const int mod = 1e9+7; const double pi = acos(-1); const double eps = 1e-8; ll n,m,a[maxn],tmp[maxn]; bool check(int val) { memcpy(tmp,a,sizeof(a)); for(int i = 1;i <= n;i++) if(tmp[i] < tmp[i-1]) { if(tmp[i-1]-tmp[i] > val) return false; tmp[i] = tmp[i-1]; } else if(tmp[i-1]+m-tmp[i] <= val) tmp[i] = tmp[i-1]; return true; } int main() { n = read(),m = read(); for(int i = 1;i <= n;i++) a[i] = read(); int l = 0,r = m,ans = m; while(l <= r) { int mid = l+r>>1; if(check(mid)) { ans = min(ans,mid); r = mid-1; } else l = mid+1; } printf("%d\n",ans); return 0; }