前言
整体评价
C题这个构造题挺好的,赛中把-1写成No, 直接整不会了,T_T.
D题是一道很裸的最小生成树题,只需要一个小小的逆向思维,把删除操作转换为构建过程。
欢迎关注
珂朵莉 牛客周赛专栏
珂朵莉 牛客小白月赛专栏
A. 小红的漂亮串
数据规模较小,直接暴力匹配即可,当然也可以使用API。
import java.io.BufferedInputStream;
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(new BufferedInputStream(System.in));String s = sc.next();int cnt = 0;int pos = 0;while (cnt < 2 && (pos = s.indexOf("red", pos)) != -1) {pos += 3;cnt++;}System.out.println(cnt >= 2 ? "Yes": "No");}}
s = input()p = 0
cnt = 0
# find 和 index的区别
while cnt < 2 and s.find("red", p) != -1:cnt += 1p = s.find("red", p) + 1print ("Yes" if cnt >= 2 else "No")
B. 小红的偶子串
好像滑窗贪心是错误的
引入dp[i + 1], 表示以i结尾,且是偶数位的最长子串(为了处理方便,漂移了一位)
-
dp[i + 1] = dp[i - 1] + 2, str[i] == str[i - 1]
-
dp[i + 1] = 0, str[i] != str[i - 1]
import java.io.BufferedInputStream;
import java.util.Arrays;
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(new BufferedInputStream(System.in));char[] str = sc.next().toCharArray();int n = str.length;int res = 0;int[] dp = new int[n + 1];for (int i = 1; i < n; i++) {if (str[i] == str[i - 1]) {dp[i + 1] = dp[i - 1] + 2;}res = Math.max(res, dp[i + 1]);}System.out.println(res);}}
s = input()n = len(s)
dp = [0] * (n + 1)dp[0] = 0
for i in range(0, n - 1):if s[i] == s[i + 1]:dp[i + 2] = max(dp[i + 2], dp[i] + 2)print (max(dp))
C. 小红的数组构造
首先可以排除掉不可能的情况
- 1~n的累加和 > x
- n > k
然后想如何构造这个神奇的数组呢?
可以先安排,1~n填充,即arr[i] = i
那这样还剩余
left = x - (n+1)*n/2
那如何处理这个剩余的部分呢?
其实可以对n进行乘除
- d = left / n
- r = left % n
把d赋值给每个元素,然后r这个尾巴相当于给最后的r个元素额外+1
这样的构造数组,应该是理想上最满足要求的数组了。
题外话:
赛中也采用了,类似后悔堆的思路,即先填充1~n,然后多余的从大到小进行置换,可以过,但是没法证明。
import java.io.BufferedInputStream;
import java.util.Scanner;
import java.util.stream.Collectors;
import java.util.stream.IntStream;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(new BufferedInputStream(System.in));int n = sc.nextInt();long k = sc.nextLong(), x = sc.nextLong();long s = ((long)n) * (n + 1) / 2;if (s > x || n > k) {System.out.println(-1);} else {long[] arr = new long[n + 1];for (int i = 1; i <= n; i++) {arr[i] = i;}x -= s;long d = x / n;long v = x % n;for (int i = 1; i <= n; i++) {arr[i] += d;if (n - i < v) {arr[i]++;}}// 对数组进行最后的check,保证每个元素都小于等于kboolean ok = true;for (int i = 1;i <= n; i++) {if (arr[i] > k) ok = false;}if (!ok) System.out.println("-1");else System.out.println(IntStream.range(1, n + 1).mapToObj(t -> String.valueOf(arr[t])).collect(Collectors.joining(" ")));}}}
D. 小红的图上删边
逆向思维,把删除转换为重头构建树,那这样就变成求最小生成树的过程了。
这边采用 kruskal算法,借助并查集来实现最小生成树的构建。
这边需要额外计算边权,其实就是统计每个点的2,5的因子数
w(u, v) = min(cnt5(u) + cnt5(v), cnt2(u) + cnt2(v))
整体的时间复杂度为 O ( m l o g m ) O(mlogm) O(mlogm), 主要在排序这块
import java.io.BufferedInputStream;
import java.util.*;public class Main {static class Dsu {int n;int[] arr;int[] gz;public Dsu(int n) {this.n = n;this.arr = new int[n + 1];this.gz = new int[n + 1];Arrays.fill(gz, 1);}int find(int u) {if (arr[u] == 0) return u;return arr[u] = find(arr[u]);}void union(int u, int v) {int ai = find(u), bi = find(v);if (ai != bi) {arr[ai] = bi;gz[bi] += gz[ai];}}int gSize(int u) {return gz[find(u)];}}public static void main(String[] args) {Scanner sc = new Scanner(new BufferedInputStream(System.in));int n = sc.nextInt(), m = sc.nextInt();Dsu dsu = new Dsu(n);long[] ws = new long[n + 1];int[] cnt5 = new int[n + 1];int[] cnt2 = new int[n + 1];for (int i = 1; i <= n; i++) {ws[i] = sc.nextLong();long v = ws[i];while (v % 5 == 0) {cnt5[i]++;v /= 5;}while (v % 2 == 0) {cnt2[i]++;v /= 2;}}long res = 0;List<int[]> edges = new ArrayList<>();for (int i = 0; i < m; i++) {int u = sc.nextInt(), v = sc.nextInt();int w = Math.min(cnt5[u] + cnt5[v], cnt2[u] + cnt2[v]);// 引入边权edges.add(new int[] {u, v, w});res += w;}// 按边权从小到大排序Collections.sort(edges, Comparator.comparing(x -> x[2]));long tmp = 0;for (int[] e: edges) {int u = e[0], v = e[1], w = e[2];if (dsu.find(u) != dsu.find(v)) {dsu.union(u, v);tmp += w;if (dsu.gSize(1) == n) {break;}}}// 删边收益 = 总的权值 - 最小生成树的权值System.out.println(res - tmp);}}
import heapqclass Dsu(object):def __init__(self, n: int):self.n = n self.arr = [0] * (n + 1) # index-1self.group = ndef find(self, u: int) -> int:if self.arr[u] == 0:return uself.arr[u] = self.find(self.arr[u])return self.arr[u]def union(self, u :int, v: int):a = self.find(u)b = self.find(v)if a != b:self.arr[a] = bself.group -= 1def groupNum(self) -> int:return self.groupn, m = list(map(int, input().split()))
arr = list(map(int, input().split())) # 逆向思维
cnt2 = [0] * (n + 1)
cnt5 = [0] * (n + 1)for i in range(len(arr)):v = arr[i]while v % 2 == 0:v /= 2cnt2[i + 1] += 1while v % 5 == 0:v /= 5cnt5[i + 1] += 1res = 0
edges = []
for i in range(m):u, v = list(map(int, input().split()))edges.append((min(cnt2[u] + cnt2[v], cnt5[u] + cnt5[v]), u, v))res += min(cnt2[u] + cnt2[v], cnt5[u] + cnt5[v])dsu = Dsu(n)
heapq.heapify(edges)while dsu.groupNum() > 1 and len(edges):row = heapq.heappop(edges)if dsu.find(row[1]) != dsu.find(row[2]):dsu.union(row[1], row[2])res -= row[0]print (res)