牛客周赛 Round 57 解题报告 | 珂学家
小红喜欢1
https://ac.nowcoder.com/acm/contest/88888/A
前言
题解
难度比较适宜,这场周赛出的不错。
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. 小红的线段
思路: 数学 + 贪心
- , 则在直线下方, 构建点集
- , 则在直线上方, 构建点集
- , 则该点恰好在直线上, 构建点集
- 优先利用构建线段
- 次之使用
- 再次之使用
- 剩下的都是没有交点的情况
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(" ")));
}
}
}
}