2024-2025 ICPC, NERC, Southern and Volga Russian Regional Contest B. Make It Equal

因为和题解有所区别,所以写一发题解增长见识。

题面

B. Make It Equal

给你一个大小为 \(n\) 的整数数组 \(a\) 。数组元素的编号从 \(1\)\(n\)

您可以执行以下任意次数的操作(可能为 0 次):从 \(1\)\(n\) 中选择一个索引 \(i\) ;将 \(a_i\) 减少 \(2\) ,并将 \(a_{(i \bmod n) + 1}\) 增加 \(1\)

执行这些操作后,数组中的所有元素都应是非负等整数

你的任务是计算最少需要执行的操作次数。

题解

考虑将 \(a_i\) 写作二进制形式,从\(0\) 位开始计数(方便描述)。

如果第 \(j(j > 0)\) 位为 \(1\)\(a_i\) 可以自减 \(2^j\),操作次数为 \(2^{j-1}\),同时对 \(1 \le t < j\) 的每个 \(a_{i + t}\)\(2^{j - t - 1}\) 次操作,可以发现,只有 \(a_{i+j}\) 的值增加了 \(1\)

循环操作之后,可以发现所有的 \(a_i\) 是小于等于 \(1\) 的,如果所有的 \(a_i\) 不都等于 \(1\),那么答案不存在,考虑退回一次操作需要让 \(a_i \ge 2\),让所有的 \(a_i \ge 1\) 后容易发现对所有位置做一次操作后回到了 \(a_i \le 1\),且恰好为原来位置的取反值,因此只有全 \(0\) 和全 \(1\) 有解。

对于最小的解只需要所有操作数减去最小操作数即可。

第一次循环操作复杂度是 \(O(n\log^2{a_i})\),第二次循环操作是 \(O(n)\) 的。

对赋值的操作精细化可以去掉第一次循环的 \(O(\log{a_i})\),用 \(\operatorname{lowbit}\) 优化直接去计算需要减去的值可以去掉对位的枚举做到 \(O(n)\)

时间复杂度 \(O(n\log^2{a_i})\) 的代码如下,\(O(n)\) 应该不难实现。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

void solve()
{
    int n;
    cin >> n;
    vector<ll> a(n), cnt(n);
    for (int i = 0; i < n; i ++ ) cin >> a[i];
    int pd = 0;
    while (!pd)
    {
        pd = 1;
        for (int i = 0; i < n; i ++ )
        {
            if (a[i] <= 1) continue;
            pd = 0;
            int t = 1;
            while (1ll << (t + 1) <= a[i]) t ++ ;
            for (int j = t; j; j -- )
            {
                if (a[i] >> j & 1)
                {
                    a[i] ^= 1ll << j;
                    a[(i + j) % n] ++ ;
                    for (int k = 0; k < j; k ++ ) cnt[(i + k) % n] += 1ll << (j - k - 1);
                }
            }
        }
    }
    int num = count(a.begin(), a.end(), 1);
    if (num != n) cout << "-1\n";
    else
    {
        ll minn = *min_element(cnt.begin(), cnt.end());
        ll res = accumulate(cnt.begin(), cnt.end(), 0) - n * minn;
        cout << res << "\n";
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int T = 1;
    cin >> T;
    while (T -- ) solve();
    return 0;
}
posted @ 2024-11-20 23:31  YipChip  阅读(13)  评论(0编辑  收藏  举报