前言

alt


题解

难度比较适宜,这场周赛出的不错。


A. 小红喜欢1

题型: 签到+语法

arr = list(map(int, input().split()))
 
print (arr.index(1) + 1)

B. 小红的树切割

思路:思维

统计边两端为同一颜色的边数即可

n = int(input())
 
s = input()
 
res = 0
for i in range(n - 1):
    u, v = list(map(int, input().split()))
    if s[u - 1] == s[v - 1]:
        res += 1
         
print (res)

C. 小红的双好数(easy)

思路: 数论 + 分类讨论

首先,2进制是天然好进制

同时需要借用一个经典结论

因此,对于大部分n,只要两数即可

所以需要考虑的是例外是

  • n = 1,3

    2,3为解

  • n = 2

    无解

n = int(input())

if n == 1 or n == 3:
    print ("YES")
    print (2, 3)
elif n == 2:
    print ("NO")
else:
    print ("YES")
    print (2, n - 1)

D. 小红的线段

思路: 数学 + 贪心

  • , 则在直线下方, 构建点集
  • , 则在直线上方, 构建点集
  • , 则该点恰好在直线上, 构建点集
  1. 优先利用构建线段
  2. 次之使用
  3. 再次之使用
  4. 剩下的都是没有交点的情况
n, k, b = list(map(int, input().split()))

def xl(x, y):
    y1 = k * x + b
    if y == y1:
        return 0
    elif y > y1:
        return 1
    return -1

pos = []
neg = []
zero = []

for i in range(2 * n):
    x, y = list(map(int, input().split()))
    d = xl(x, y)
    if d==0:
        zero.append(i + 1)
    elif d > 0:
        pos.append(i + 1)
    else:
        neg.append(i + 1)

ans = 0
res = []
while len(pos) > 0 and len(neg) > 0:
    t1, t2 = pos.pop(), neg.pop()
    res.append((t1, t2, 'Y'))
    ans += 1
    
while len(zero) > 0 and len(pos) > 0:
    t1, t2 = zero.pop(), pos.pop()
    res.append((t1, t2, 'Y'))
    ans += 1
    
while len(zero) > 0 and len(neg) > 0:
    t1, t2 = zero.pop(), neg.pop()
    res.append((t1, t2, 'Y'))
    ans += 1
    
while len(zero) >= 2:
    t1, t2 = zero.pop(), zero.pop()
    res.append((t1, t2, 'Y'))
    ans += 1
        
while len(pos) >= 2:
    t1, t2 = pos.pop(), pos.pop()
    res.append((t1, t2, 'N'))
    
while len(neg) >= 2:
    t1, t2 = neg.pop(), neg.pop()
    res.append((t1, t2, 'N'))
        
print (ans)
for e in res:
    print (*e, sep=' ')


E. 小红的双好数(hard)

题型: 数论+枚举

所求的数,满足

同时满足

因为 , 所以尝试构造枚举 的序列出发,然后验证满足某个

因为

所以 在 范围内

满足序列的个数,最多为

k2 最大的指数 状态数
3
4
5
6

分类讨论下

  • ,其实可以打表(实际上不需要,解空间很小)
  • , 状态空间已经很小,可暴力全枚举
def check(v, k):
    while v > 0:
        r = v % k
        if r > 1:
            return False
        v //= k
    return True

def solve():
    k1, k2 = list(map(int, input().split()))
    dp = [0]
    base = k2
    while base <= 10 ** 18:
        dp2 = dp[:]
        for v in dp:
            if check(v + base, k1):
                return v + base
            dp2.append(v + base)
        base = base * k2
        dp = dp2
    return -1

ans = solve()
if ans == -1:
    print ("NO")
else:
    print ("YES")
    print (ans)


F. 小红的数组操作

思路: 树套树

不太确定,出题人是否出于这个想法。

但是无论怎么样,线段树中套平衡二叉树,是一种可行的解法。

当然很多同学,在写题的时候,可能会没意识到这点。

前缀最小,更一般化也可以理解为区间最小,那就是RMQ。

这边是区间查询+点更新操作。

// package lc.temp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
import java.util.TreeMap;

public class Main {

    static int inf = Integer.MAX_VALUE;

    static class SegTree {
        int l, r, m;
        int minValue;
        public SegTree left, right;
        public SegTree(int ul, int ur) {
            this.l = ul;
            this.r = ur;
            this.m = (l + r) / 2;
            this.minValue = inf;

            if (l == r) {
                return;
            }
            this.left = new SegTree(ul, m);
            this.right = new SegTree(m + 1, ur);
        }

        void update(int p, int v) {
            if (l == r) {
                this.minValue = v;
                return;
            }
            if (p <= m) {
                this.left.update(p, v);
            } else {
                this.right.update(p, v);
            }
            this.minValue = Math.min(this.left.minValue, this.right.minValue);
        }

        int query(int p) {
            if (l == r) {
                return this.minValue;
            }
            if (p >= r) {
                return this.minValue;
            }
            if (m >= p) {
                return this.left.query(p);
            } else {
                return Math.min(this.left.minValue, this.right.query(p));
            }
        }

    }


    public static void main(String[] args) {
        AReader sc = new AReader();
        int t = 1;
        while (t-- > 0) {
            int n = sc.nextInt();
            TreeMap<Integer, Integer>[] ts = new TreeMap[n];
            int[][] arr = new int[n][];
            for (int i = 0; i < n; i++) {
                int m = sc.nextInt();
                ts[i] = new TreeMap<>();
                arr[i] = new int[m];
                for (int j = 0; j < m; j++) {
                    int v = sc.nextInt();
                    ts[i].merge(v, 1, Integer::sum);
                    arr[i][j] = v;
                }
            }

            SegTree segTree = new SegTree(0, n - 1);
            for (int i = 0; i < n; i++) {
                segTree.update(i, ts[i].firstKey());
            }


            int q = sc.nextInt();
            for (int i = 0; i < q; i++) {
                int op = sc.nextInt();
                if (op == 1) {
                    int x = sc.nextInt(), y = sc.nextInt();
                    x--; y--;
                    int v = sc.nextInt();

                    int ov = arr[x][y];
                    if (ov == v) continue;

                    ts[x].computeIfPresent(ov, (a, b) -> b > 1 ? b - 1: null);
                    arr[x][y] = v;
                    ts[x].merge(v, 1, Integer::sum);

                    segTree.update(x, ts[x].firstKey());
                } else {
                    int x = sc.nextInt();
                    x--;
                    int res = segTree.query(x);
                    System.out.println(res);
                }
            }
        }

    }

    static
    class AReader {
        private BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        private StringTokenizer tokenizer = new StringTokenizer("");
        public String nextLine() {
            tokenizer = new StringTokenizer("");
            return innerNextLine();
        }
        public String next() {
            hasNext();
            return tokenizer.nextToken();
        }
        public int nextInt() {
            return Integer.parseInt(next());
        }
        public long nextLong() {
            return Long.parseLong(next());
        }
        private String innerNextLine() {
            try {
                return reader.readLine();
            } catch (IOException ex) {
                return null;
            }
        }
        public boolean hasNext() {
            while (!tokenizer.hasMoreTokens()) {
                String nextLine = innerNextLine();
                if (nextLine == null) {
                    return false;
                }
                tokenizer = new StringTokenizer(nextLine);
            }
            return true;
        }
    }

}

唯一的其他想法是,是否还可以借助其他数据结构实现?


G. 小红的双排列构造

思路: 构造

其实这题的指向很明确

然后把剩下的1~n围绕其左右侧,使得正好的排列数为K

策略:

  • 先左侧构建一个 1~N的数组

  • 那右侧天然就是一个1~N的数组

  • 然后从左侧,依次构造 k - 2的排列数

  • 剩下的何如阻断呢?其实打断它的循环节即可


对于特殊的情况,比如k=0,n=1,这些组合需要特判

写了一个很奇怪的代码

import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(new BufferedInputStream(System.in));
        int n = sc.nextInt(), k = sc.nextInt();

        if (k == 0) {
            if (n <= 2) {
                System.out.println("-1");
            } else {
                List<Integer> res = new ArrayList<>();
                for (int i = 0; i < n; i++) {
                    res.add(i + 1);
                    res.add(i + 1);
                }
                System.out.println(res.stream().map(String::valueOf).collect(Collectors.joining(" ")));
            }
        } else {
            if (n == 1) {
                if (k == 1) {
                    System.out.println(-1);
                } else if (k==2) {
                    System.out.println("1 1");
                }
            } else if (k == 1) {
                List<Integer> res = new ArrayList<>();
                res.add(1);
                for (int i = 0; i < n; i++) {
                    res.add(i + 1);
                }
                for (int i = 1; i < n; i++) {
                    res.add(i + 1);
                }
                System.out.println(res.stream().map(String::valueOf).collect(Collectors.joining(" ")));
            } else {
                List<Integer> res = new ArrayList<>();
                for (int i = 0; i < n; i++) {
                    res.add(i + 1);
                }
                for (int i = 0; i < k - 2; i++) {
                    res.add(i + 1);
                }
                for (int i = k - 2; i < n; i++) {
                    res.add(n - (i - k + 2));
                }
                System.out.println(res.stream().map(String::valueOf).collect(Collectors.joining(" ")));
            }
        }
    }
}

写在最后

alt