zoukankan      html  css  js  c++  java
  • Codeforces Round #631 (Div. 1)

    Codeforces Round #631 (Div. 1)

    A

    B

    由题意得,(a_i) 二进制下最高位的 (1) 一定大于 (a_{i-1}) 的,并且只需要满足这一个条件。那么只需要计算出 (p_i) 表示最高二进制位为 (i) 时有多少种数,前面都是 (2^k) 的形式,最后一个要特判。然后每一位也可以不选,但不能全都不选,所以 (res=(prod(p_i+1))-1)

    void solve () {
        int d, m, res = 1;
        read (d), read (m);
        for (int i = 0; i <= 30; ++i) {
            if ((1ll << i + 1) - 1 < d) {
                res = res * ((1 << i) + 1) % m;
            } else {
                res = res * (d - (1 << i) + 2) % m; break;
            }
        }
        printf ("%lld
    ", (res + m - 1) % m);
    }
    

    C

    贪心的删除,每次删能删的最大的那个(略)

    D

    (a)(a_i=a_{i+1}) 的地方被分割,弄一个新的字符串 (b) 只记录这些分割的字符,即依次在 (b) 中加入 (a_i=a_{i+1})(a_i)。把在 (a) 中的删除对应到 (b) 中就是:1、删除一个 (b_i);2、删除满足 (b_i e b_{i+1})(i,i+1)。也就是要尽量多用操作 (2) 删光 (b)

    设当前出现最多的是 (x),出现了 (c) 次。

    1、(2c ge |b|),可以让其它所有的字符和 (x) 来一次操作 (2),用栈维护一下,剩下的 (x) 单独删。

    2、(2c< |b|),先贪心的执行操作 (2),直到 (2c=|b|),然后变成第一种情况

    输出方案需要用线段树维护一下当前的真实下标

    const int N = 2e5 + 5;
    int n, m, now, cnt[30], mx, p; char a[N];
    int tp, t[N], res;
    vector<pair<int, int> > ans;
    pair<int, int> b[N];
    #define fi first
    #define se second
    struct tree {
        int c[N << 2], tag[N << 2];
        #define ls (p << 1)
        #define rs (p << 1 | 1)
        void clear () {
            for (int i = 1; i <= 4 * n; ++i) c[i] = tag[i] = 0;
        }
        void push_down (int p, int l, int r) {
            if (!tag[p]) return;
            int mid (l + r >> 1);
            c[ls] = mid - l + 1, c[rs] = r - mid;
            tag[ls] = tag[rs] = 1; tag[p] = 0;
        }
        void modify (int p, int l, int r, int ql, int qr) {
            if (ql <= l && r <= qr) {
                c[p] = r - l + 1, tag[p] = 1; return;
            }
            int mid (l + r >> 1); push_down (p, l, r);
            if (ql <= mid) modify (ls, l, mid, ql, qr);
            if (qr > mid) modify (rs, mid + 1, r, ql, qr);
            c[p] = c[ls] + c[rs];
        }
        int query (int p, int l, int r, int ql, int qr) {
            if (ql <= l && r <= qr) return c[p];
            int mid (l + r >> 1), s = 0; push_down (p, l, r);
            if (ql <= mid) s += query (ls, l, mid, ql, qr);
            if (qr > mid) s += query (rs, mid + 1, r, ql, qr);
            return s;
        }
    } u;
    void del (int l, int r) {
        int L = l - u.query (1, 1, n, 1, l);
        int R = r - u.query (1, 1, n, 1, r);
        if (!L) L = 1; if (!R) R = 1;
        ++res; ans.emplace_back (L, R);
        u.modify (1, 1, n, l, r);
        --cnt[a[l] - 'a'];
        if (r < n) --cnt[a[r] - 'a'];
    }
    void solve_a () {
        tp = 0;
        for (int i = 1; i <= m; ++i) {
            if (!tp) { t[++tp] = i; continue; }
            if (b[t[tp]].fi == p) {
                if (b[i].fi == p) t[++tp] = i;
                else del (b[t[tp]].se + 1, b[i].se), --tp;
            } else {
                if (b[i].fi != p) t[++tp] = i;
                else del (b[t[tp]].se + 1, b[i].se), --tp;
            }
        }
        if (!tp) return del (1, n), void ();
        while (tp > 1) del (b[t[tp - 1]].se + 1, b[t[tp]].se), --tp;
        del (1, b[t[1]].se), del (b[t[1]].se + 1, n);
    }
    void solve_b () {
        if (m & 1) del (b[m].se + 1, n), --m, --now;
        tp = 0;
        for (int i = 1; i <= m; ++i) {
            for (int j = 0; j < 26; ++j)
                if (cnt[j] * 2 >= now) {
                    p = j; int mm = 0;
                    for (int k = 1; k <= tp; ++k) b[++mm] = b[t[k]];
                    for (int k = i; k <= m; ++k) b[++mm] = b[k];
                    m = mm;
                    return solve_a (), void ();
                }
            if (!tp || b[t[tp]].fi == b[i].fi)
                { t[++tp] = i; continue; }
            del (b[t[tp]].se + 1, b[i].se), --tp, now -= 2;
        }
        del (1, n);
    }
    signed main() {
        int T; read (T);
        while (T--) {
            scanf ("%s", a + 1);
            n = strlen (a + 1); m = 0;
            for (int i = 1; i < n; ++i)
                if (a[i] == a[i + 1]) b[++m] = {a[i] - 'a', i};
            memset (cnt, 0, sizeof (cnt));
            for (int i = 1; i <= m; ++i) ++cnt[b[i].fi];
            mx = 0; now = m;
            for (int i = 0; i < 26; ++i)
                if (cnt[i] > mx) mx = cnt[i], p = i;
            res = 0, ans.clear (), u.clear ();
            mx * 2 >= m ? solve_a () : solve_b ();
            printf ("%d
    ", res);
            for (auto i : ans) printf ("%d %d
    ", i.fi, i.se);
        }
        return 0;
    }
    

    E

    原本存在的 (A) 将字符串划分为若干段,设每段长度为 (l_i),共 (s) 段。新的 (A) 一定是尽量平均分布最优,那么一组答案 ((L,R)) 可行,需要满足两个条件

    1、([lceilfrac{l_i}{R} ceil-1,lfloorfrac{l_i}{L} floor-1]) 区间非空

    2、(sumlceilfrac{l_i}{R} ceil-sleq kleq sumlfloorfrac{l_i}{L} floor-s)

    对于第二个条件,(L,R) 相互独立,可以直接二分出来最大的 (L') 和最小的 (R')。然后分类

    1、(L'ge R'),答案为 (0)。此时取任意 (L=Rin[R',L']),第二个条件已经满足,而对于第一个条件,因为 (sumlceilfrac{l_i}{R} ceilleq sumlfloorfrac{l_i}{L} floor)(lceilfrac{l_i}{R} ceilge lfloorfrac{l_i}{L} floor),所以 (forall i,lceilfrac{l_i}{R} ceil=lfloorfrac{l_i}{L} floor),第一个条件也成立。其实,若 (L'ge R'),必有 (L'=R')

    2、(L'<R'),此时需要考虑第一个条件。(frac{l_i}{L'}>frac{l_i}{R'}Rightarrow lfloorfrac{l_i}{L} floor-lceilfrac{l_i}{R} ceilge-1)。因为如果不满足,差为 (-1),那么最优方案只需要移动 (L',R') 中的一个即可。也就是会多出一些限制 ((a_i,b_i)),表示 (L'leq a_i)(R'ge b_i),选一些移动 (L'),一些移动 (R'),让 (R'-L') 最小。排个序算算

    const int N = 4e5 + 5;
    int n, m, k, p[N], l[N];
    int L, R;
    int f (int x, int o) {
        int s = 0;
        for (int i = 1; i <= m; ++i) s += l[i] / x;
        if (o) {
            for (int i = 1; i <= m; ++i) s += (l[i] % x != 0);
        }
        return s;
    }
    void getLR () {
        int l = 1, r = n, mid; L = 1;
        while (l <= r) {
            mid = l + r >> 1;
            int t = f (mid, 0);
            if (t < m + k) r = mid - 1;
            else L = mid, l = mid + 1;
        }
        l = 1, r = n, R = n;
        while (l <= r) {
            mid = l + r >> 1;
            int t = f (mid, 1);
            if (t > m + k) l = mid + 1;
            else R = mid, r = mid - 1;
        }
    }
    pair<int, int> a[N]; int mx[N];
    #define fi first
    #define se second
    int solve () {
        int tot = 0, res = 1e16;
        for (int i = 1; i <= m; ++i) {
            int x = l[i] / R + (l[i] % R != 0), y = l[i] / L;
            if (x > y) {
                a[++tot].fi = l[i] / x;
                a[tot].se = y ? l[i] / y + (l[i] % y != 0) : 1e16;
            }
        }
        a[++tot] = {L, 1e16}, a[++tot] = {-1e16, R};
        sort (a + 1, a + tot + 1);
        for (int i = 1; i <= tot; ++i)
            mx[i] = max (mx[i - 1], a[i].se);
        for (int i = 2; i <= tot; ++i)
            res = min (res, mx[i - 1] - a[i].fi);
        return res;
    }
    signed main() {
        int T; read (T);
        while (T--) {
            read (n), read (m), read (k);
            ++m, p[1] = 0, p[m + 1] = n;
            for (int i = 2; i <= m; ++i) read (p[i]);
            for (int i = 1; i <= m; ++i) l[i] = p[i + 1] - p[i];
            getLR ();
            if (L >= R) { puts ("0"); continue; }
            printf ("%lld
    ", solve ());
        }
        return 0;
    }
    
  • 相关阅读:
    discuz_ucenter_api_for_java的中文问题
    java的编码问题详解
    java的泛型的技巧
    向maven中央仓库提交jar
    Java并发之FutureTask
    java并发之Semaphore
    centos中JDK版本冲突的问题
    C++中嵌入Python
    boost::python的使用
    c++调用python引号的问题
  • 原文地址:https://www.cnblogs.com/whx666/p/631-div1.html
Copyright © 2011-2022 走看看