Contestant'. Rank 753. Rating +35.

A. Unit Array

题意

给定一个由 \(1, -1\) 组成的数组 \(a\),定义操作为选择一个元素,并将其改为它的相反数。

现在,输出最小的操作数,使最后的数组满足下面的条件:

  1. \(a_1 + a_2 + \ldots + a_n \ge 0\)

  2. \(a_1 \cdot a_2 \cdot \ldots \cdot a_n = 1\)

思路

我们简化一下条件:

  1. \(1\) 的个数大于等于 \(-1\) 的个数;

  2. \(-1\) 的个数为偶数

因而,我们分讨即可。

时间复杂度:\(O(n)\)

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>
#define ppii pair<int, pii>
#define pci pair<char, int>
#define fs first
#define sc second
#define pb emplace_back
#define all(x) x.begin(),x.end()

const int N = 2e5 + 10, mod = 998244353, inf = 0x3f3f3f3f3f3f3f3f;

void solve() {
    int n;
    cin >> n;
    int p = 0;
    for(int i=0;i<n;i++){
        int cur;
        cin >> cur;
        if(cur == 1) p ++;
    }
    int q = n - p;
    if(p >= q && q % 2 == 0){
        cout << 0 << '\n';
    }else{
        int ans = 0;
        if(p < q) {
            ans += (q - p + 1) / 2;
            q -= (q - p + 1) / 2;
        }
        if(q % 2 == 1) ans ++;
        cout << ans << '\n';
    }
}

signed main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while(t --) solve();
}

但是分讨后式子得推一下(

B. Maximum Strength

题意

给定两个大数 \(L, R\),找出 \(a, b\),满足 \(L \leq a \leq b \leq R\),并且 \(a\)\(b\) 的所有位之差的绝对值之和最大,输出这个最大值。

思路

我们考虑贪心。

首先,对于单独一位,不难发现 \(9 - 0\) 得到的差值最大,那么我们自然希望能构造尽可能多的 \(9, 0\)

我们不妨将其放在最后几位,构造形如 \(\ldots000, \dots999\) 的数。

如何构造?举个例子:

114514 114810

你会发现,\(1145\)\(\color{rgb(124,179,66)}{99}\)\(, 1148\)\(\color{rgb(124,179,66)}{00}\) 即为我们需要的构造。

因而,我们得到下面的结论:

  1. 以字符串方式读入大数,循环补齐前导0;

  2. 从头开始遍历,找出第一个不相同的位置,记录差值 \(dis\)

  3. 从第一个不相同的位置的下一个位置开始,每一位差值都视为 \(9\)

  4. 最后的答案就是 \(dis\) 加上若干个 \(9\)

证明是显然的。

时间复杂度:\(O(n)\)

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>
#define ppii pair<int, pii>
#define pci pair<char, int>
#define fs first
#define sc second
#define pb emplace_back
#define all(x) x.begin(),x.end()

const int N = 2e5 + 10, mod = 998244353, inf = 0x3f3f3f3f3f3f3f3f;

void solve() {
    string a, b;
    cin >> a >> b;
    int n = max(a.size(), b.size());
    int difa = n - a.size(), difb = n - b.size();
    for(int i=0;i<difa;i++) a = "0" + a;
    for(int i=0;i<difb;i++) b = "0" + b;
    int ans = 0;
    for(int i=0;i<n;i++){ //找出第一个不同的位置,前面先算0
        if(ans != 0){
            ans += 9;
            continue;
        }
        if(a[i] == b[i]) continue;
        ans = abs(a[i] - b[i]);
    }
    cout << ans << '\n';
}

signed main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while(t --) solve();
}

群友:如果你觉得这是数位 \(dp\),那你一定是学算法学魔怔了

C. Game with Reversing

题意

定义在两个长度相等的字符串 \(S, T\) 上的博弈:

  1. \(Alice\) 可选定任意一个字符串的任意一个元素,并将其替换为任意一个字符;

  2. \(Bob\) 可选定任意一个字符串,并将其整个翻转

定义任意一个玩家必须执行对应的操作,输出让两个字符串变为相同需要的操作总和。

为此,\(Alice\) 会让两个字符串变得尽可能相同,而 \(Bob\) 相反,会让两个字符串变得尽可能不同。

思路

我们考虑翻转操作的特点:

  1. 对同一个字符串执行两次翻转,等于没有翻转;

  2. 对不同的两个字符串各执行一次翻转,等效于没有翻转(因为如果翻转后相等,那么就等价于翻转前相等)

因而,我们不难发现,\(Bob\) 执行两次操作就约等于没操作,他只能让两个字符串在某个顺序要变为一致时,提前翻转一下,来让操作数变多一点。

我们考虑只翻转 \(T\),那么,我们只需分别统计让 \(S\) 变为 \(T\) 和 翻转 \(T\) 所需的操作数,然后针对奇偶性分讨即可。

注意,分讨的时候,如果翻转后两个字符串一致,最后的操作数是 \(2\),而非 \(0\) (\(Alice\) 随便选一个,改成一样的字符,然后由 \(Bob\) 翻转)。

时间复杂度:\(O(n)\)

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>
#define ppii pair<int, pii>
#define pci pair<char, int>
#define fs first
#define sc second
#define pb emplace_back
#define all(x) x.begin(),x.end()

const int N = 2e5 + 10, mod = 998244353, inf = 0x3f3f3f3f3f3f3f3f;

void solve() {
    int n;
    cin >> n;
    string a, b;
    cin >> a >> b;
    string c = b;
    reverse(all(c));
    int cnt1 = 0 , cnt2 = 0;
    for(int i=0;i<n;i++){
        if(a[i] != b[i]) cnt1 ++;
    }
    for(int i=0;i<n;i++){
        if(a[i] != c[i]) cnt2 ++;
    }
    if(cnt1 != 0) {
        if (cnt1 % 2 == 0) cnt1 = cnt1 * 2;
        else cnt1 = (cnt1 - 1) * 2 + 1;
    }
    if(cnt2 != 0) {
        if (cnt2 % 2 == 1) cnt2 = cnt2 * 2;
        else cnt2 = (cnt2 - 1) * 2 + 1;
    }else cnt2 = 2;
    cout << min(cnt1, cnt2) << '\n';
}

signed main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while(t --) solve();
}

Bob: 我博弈了个寂寞