zoukankan      html  css  js  c++  java
  • CodeForces

    Increasing by Modulo

    题目大意:

    选一个下标的长度为(k)的子序列(b_1,b_2,...,b_k),使得(a_{b_i} = (a_{b_i} + 1) \% m),求使得序列满足单调非降的最小操作次数。

    思路:

    (f(x))为能否经过(x)次操作数使得序列满足条件,不难看出这是一个单调函数,考虑利用二分求出最小操作次数,假设当前的二分的操作次数为(x)

    对于check的编写,我们首先考虑到,题目中的操作对于序列第(i)位数字(a[i])的变换是相对独立的,也就是说,我们只需check序列经过(x)次变换后的结果序列,即判断每个数字的变换次数是否符合当前二分的(x),并且判断能否让结果序列满足单调非降。

    对于确定二分操作次数的上界,我们考虑到,经过(m)次变换之后,我们一定可以将所有数字都变为(0),由此确定出二分上界。

    接下来,我们贪心的进行变换。

    假设当前check到第(i)位数字(a[i])

    1. 如果(a[i] = a[i - 1]),不需要进行变换。
    2. 如果(a[i] < a[i - 1]),要想满足单调不降就需要对(a[i])进行操作,如果(a[i])(a[i - 1])的距离大于了二分的次数(x),直接return,否则,使(a[i] := a[i - 1]),让序列升的不那么多(这里是不让他上升)以贪心的期望后面会更加容易的满足单调非降。
    3. 如果(a[i] > a[i - 1]),那么如果能变为(a[i - 1])就变为(a[i - 1]),否则不改变。

    举个例子

    a[i - 1]   a[i]
        5        3
        4        7
    

    主要是a[i] > a[i - 1]时:

      a[i - 1]
    |----------|
             a[i]                    m
    |-----------****************|--------------|
    

    因为操作是加操作,所以除非满足(m - (a[i] - a[i - 1]) leq x),使得(a[i])变换为(a[i - 1]),否则,(a[i])只能落在上图‘*’号的左边或者右边,落在左边则不满足单调不降的条件,落在右边则还不如不变换。

    Code:
    #include <bits/stdc++.h>
    using namespace std;
    using ll = long long;
    using pii = pair<int, int>;
    const double eps = 1e-6;
    const int N = 300010;
    //const int N = 10;
    const int INF = 0x3f3f3f3f;
    const int mod = 1000000007; //998244353
    const int dir[8][2] = {0, 1, 0, -1, 1, 0, -1, 0,/* dir4 */ -1, -1, -1, 1, 1, -1, 1, 1};
    ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }
    ll powmod(ll a, ll b) { ll res = 1; a %= mod; assert(b >= 0); for (; b; b >>= 1) { if (b & 1) res = res * a % mod; a = a * a % mod; } return res; }
    template<class T> bool ckmin(T& a, const T& b) { return b < a ? a = b, 1 : 0; }
    template<class T> bool ckmax(T& a, const T& b) { return a < b ? a = b, 1 : 0; }
    
    ll n, m, a[N], oa[N];
    
    bool ck(ll x) {
        for (int i = 1; i <= n; i++)
            a[i] = oa[i];
        for (ll i = 1; i <= n; i++) {
            if (a[i] == a[i - 1]) {
                continue;
            } else if (a[i] < a[i - 1]) {
                if (a[i - 1] - a[i] > x) {
                    return false;
                } else {
                    a[i] = a[i - 1];
                }
            } else {
                if (m - (a[i] - a[i - 1]) <= x) {
                    a[i] = a[i - 1];
                }
            }
        }
        return true;
    }
    
    int main() {
        ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        cin >> n >> m;
        for (int i = 1; i <= n; i++) {
            cin >> oa[i];
        }
        ll lf = 0, rt = m/* m次操作可以让所有数都变为0 */, mid;
        while (lf < rt) {
            mid = (lf + rt) >> 1;
            if (ck(mid)) {
                rt = mid;
            } else {
                lf = mid + 1;
            }
        }
        cout << lf << "
    ";
        return 0;
    }
    
  • 相关阅读:
    nginx
    同步和异步
    什么是ACID
    关系型数据库特点小结
    js 简单小知识
    join 和 left join 和 right join的区别?
    mysql中having和where区别?
    include和require区别
    什么是脏读,不可重复,幻读?
    Mysql常见面试题
  • 原文地址:https://www.cnblogs.com/Nepenthe8/p/14808983.html
Copyright © 2011-2022 走看看