【解题总结】Codeforces Round 673 (Div. 1)

A k-Amazing Numbers

题意:给定长为 n n n 的序列,对于每个 k ∈ [ 1 , n ] k \in [1, n] k[1,n] 问在每个长为 k k k 的子段中都出现过的数中最小的是多少(可能不存在)。

对序列中每种数 a a a 看其之间最大间隔是多少,设为 t t t,那么所有 ≥ t \ge t t k k k 的答案存在,且至多是 a a a

于是做一个后缀 min 即可。

B Make Them Equal

题意:给定长为 n n n 的正整数序列,每次可以选定 i , j ∈ [ 1 , n ] i, j \in [1, n] i,j[1,n] x ≥ 0 x \ge 0 x0,让 a i a_i ai 减少 i x ix ix,让 a j a_j aj 增加 i x ix ix。需保证操作完 a i ≥ 0 a_i \ge 0 ai0。问能否在 3 n 3n 3n 次操作内让所有数均相同,能的话给出方案。

这是那种一眼看上去就大概能会的题,但是我 WA 了 13 发…

在这里插入图片描述

无解容易判定:只要和不是 n n n 的倍数就无解。后面构造的基本思想是先对于所有 > 1 >1 >1 i i i,收集 a i a_i ai a 1 a_1 a1,然后再让 a 1 a_1 a1 把所有其他数变成目标(就是最后要全部变成的那个数)。

所谓收集,指的就是先用一次操作,从 a 1 a_1 a1 借走一定大小,让 a i a_i ai 变成能被 i i i 整除,然后用一次操作把 a i a_i ai 直接加到 a 1 a_1 a1 上。

这里就比较 trick:我一开始以为 a i < i a_i < i ai<i 时是直接无解,于是搞了很久,后面又尝试了各种方法才勉强通过。后面看题解发现收集这一阶段其实只要按照 i = 2 , … , n i=2, \ldots, n i=2,,n 收集即可。

原因很简单,由于原始序列是正整数序列,从而初始时 a 1 ≥ 1 a_1 \ge 1 a11。我们可以归纳证明这么收集到 a i a_i ai 时, a 1 ≥ i a_1 \ge i a1i。那么这就保证了上面的收集操作不会出现 a 1 a_1 a1 不够借给 a i a_i ai 的情况。

C XOR Inverse

题意:给定一个序列,找出最小的 x x x 使得原序列每个数异或上 x x x 后逆序对数最小。

从高到低做,每次看要不要在最高位上异或一个 1。无论要不要,我们最后都不需要考虑最高位不同的数之间逆序对的贡献(因为这一步已经算完了)。

然后类似归并,把原序列分割为两个子序列(子序列中的数保持原有顺序),一个子序列中所有数最高位为 0,另一个为 1。现在逆序对只会来自这两个子序列各自的内部。于是递归下去计算即可。

int n, a[300005], maxi, b[300005];
set<int> endpoint;
int llst[300005], ttot;
pair<ll, ll> get(int l, int r, int highbit){
    
    
    // return number of inversions
    ll inv1 = 0, inv2 = 0;
    int cnt0 = 0, cnt1 = 0;
    REP(i, l, r){
    
    
        if (a[i] & highbit){
    
    
            inv2 += cnt0;
            ++cnt1;
        } else {
    
    
            inv1 += cnt1;
            ++cnt0;
        }
    }
    return make_pair(inv1, inv2);
}
int split(int l, int r, int highbit){
    
    
    int ccnt = 0;
    REP(i, l, r){
    
    
        if (!(a[i] & highbit)) ++ccnt;
    }
    if (ccnt == r - l + 1) return -1;
    int lpos = l, rpos = l + ccnt;
    REP(i, l, r){
    
    
        if (!(a[i] & highbit)) b[lpos++] = a[i];
        else b[rpos++] = a[i];
    }
    REP(i, l, r) a[i] = b[i];
    return l + ccnt - 1;
}
void init(){
    
    
    n = read();
    maxi = 0;
    REP(i, 1, n) a[i] = read(), maxi = max(maxi, a[i]);
}
void solve(){
    
    
    int logg = 1;
    while (logg <= maxi) logg <<= 1;
    logg >>= 1;
    endpoint.insert(n);
    int x = 0;
    ll totinv = 0;
    while (logg > 0){
    
    
        int lst = 1;
        ll inv0 = 0, inv1 = 0;
        for (int x: endpoint){
    
    
            auto p = get(lst, x, logg);
            inv0 += p.first, inv1 += p.second;
            lst = x + 1;
        }
        if (inv0 > inv1){
    
    
            x |= logg;
            REP(i, 1, n) a[i] ^= logg;
        }
        totinv += min(inv0, inv1);
        lst = 1;
        ttot = 0;
        for (int x: endpoint){
    
    
            int mid = split(lst, x, logg);
            if (mid > 0) llst[++ttot] = mid;
            lst = x + 1;
        }
        REP(i, 1, ttot) endpoint.insert(llst[i]);
        logg >>= 1;
    }
    printf("%lld %d\n", totinv, x);
}

D

待补。。。

E

待补。。。

F

待补。。。

猜你喜欢

转载自blog.csdn.net/zqy1018/article/details/108859439
今日推荐