Practice.

代码略去了快读模板

A. Add Plus Minus Sign

题意

给定一个长度为 \(n\) 的二进制字符串,输出 \(n-1\) 个加减运算符,满足最后的结果的绝对值最小。

思路

无视第一位,配对 \(1,1\),对每一对输出 \(-,+\),剩余的 \(1\) 输出 \(-\),剩余的 \(0\) 输出任意符号。

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

对应AC代码

import java.io.*;
import java.math.*;
import java.util.*;
import java.util.concurrent.atomic.*;

public class Main{

    public static void main(String[] args) throws Exception{
        Console console = new Console();
        int t = console.nextInt();
        while(t -- > 0){
            int n = console.nextInt();
            char[] input = console.next().toCharArray();
            int pre = -1, now = input[0] - '0';
            char[] ans = new char[n - 1];
            if(now == 1) pre = -2;
            for(int i=0;i<n-1;i++){
                now = input[i + 1] - '0';
                if(now == 0) ans[i] = '+';
                else{
                    if(pre == -1) pre = i;
                    else{
                        if(pre != -2) ans[pre] = '+';
                        ans[i] = '-';
                        pre = -1;
                    }
                }
            }
            if(pre != -1 && pre != -2) ans[pre] = '+';
            console.println(String.valueOf(ans));
        }
        console.close();
    }
}

略微简单的打卡题

B. Coloring

题意

给定 \(m\) 种颜色的数量,总量为 \(n\),将长度为 \(n\) 的序列染上色,满足所有长度为 \(k\) 的连续子序列内没有相同的颜色,输出方案是否存在。

思路

我们不妨开一个数组记录所有的数量,然后降序排序。

显然,若一个颜色 \(p\)\(x\) 位置出现了,那么在 \([x + 1, x + k - 1]\) 内都不能出现 \(p\),那么我们不妨将序列按 \(k\) 分段,那么段数即为 \(d = \lceil \frac{n}{k} \rceil\)

遍历排序后的数组,若 \(a_i > d\),那么就是无解的,输出 \(NO\) 即可,否则,我们只需将剩余的最少的颜色取出来和它一起配对为一个长为 \(d\) 的组合。

当然,配对次数过多时,我们会发现段数会减少 \(1\),此时若能满足条件,就可以直接输出 \(YES\) 了。

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

对应AC代码

import java.io.*;
import java.math.*;
import java.util.*;
import java.util.concurrent.atomic.*;

public class Main{

    public static void main(String[] args) throws Exception{
        Console console = new Console();
        int t = console.nextInt();
        while(t -- > 0){
            int n = console.nextInt(), m = console.nextInt(), k = console.nextInt();
            Integer[] a = new Integer[m];
            for(int i=0;i<m;i++) a[i] = console.nextInt();
            Arrays.sort(a, Comparator.comparingInt(o -> -o));
            int d = n / k + (n % k == 0 ? 0 : 1), l = n % k;
            boolean ans = true;
            for(int i=0;i<n;i++){
                int cur = a[i];
                if(cur > d) {
                    ans = false;
                    break;
                }
                if(l == 0) break;
                l --;
                if(l == 0) d --;
            }
            console.println(ans ? "YES" : "NO");
        }
        console.close();
    }
}

有点小贪心,因为不用考虑拿什么出来组合

C. Ice and Fire

题意

对于 \(n\) 个选手,选手 \(i\) 的能力值为 \(i\)。给定一个长为 \(n - 1\) 的二进制字符串 \(s\)\(s_i\) 表示第 \(i\) 次比赛的输赢判定,\(0\) 则能力值低者胜,否则高者胜。对于所有 \(x \in [2,n]\),输出选择不超过 \(x\) 个选手进行比赛,最后有多少个选手有机会成为胜者。

比赛机制为选择任意两个选手进行比赛,直至剩余最后一人,判定该选手为胜者。

思路

显然地,最后的获胜情况和最后一个输赢判定有直接关系。

更进一步地说,最后一段相同连续区间的长度决定了胜者的数量。

举一个例子,若 \(s\)\(\ldots,1,0,0,0,0\),那么能力值最大的三个选手一定不可能成为赢家,而恰好剩余的选手经过一定的排序都可以成为赢家。

因而,我们唯一关心的就是从后往前第一个不同的字符出现的位置,对于所有 \(x\),输出数量即可。

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

对应AC代码

import java.io.*;
import java.math.*;
import java.util.*;
import java.util.concurrent.atomic.*;

public class Main{

    public static void main(String[] args) throws Exception{
        Console console = new Console();
        int t = console.nextInt();
        while(t -- > 0){
            int n = console.nextInt();
            char[] in = console.next().toCharArray();
            int p0 = 1, p1 = 1;
            for(int i=1;i<n;i++){
                int now = in[i - 1] - '0';
                if(now == 0){
                    p0 = i + 1;
                    console.print(p1 + " ");
                }else{
                    p1 = i + 1;
                    console.print(p0 + " ");
                }
            }
            console.println();
        }
        console.close();
    }
}

想通了就很简单的思维题