json json 常用函数
函数
输入
输出
json.loads()
JSON 字符串
Python 对象
json.dumps()
Python 对象
JSON 字符串
json.load()
JSON 文件
Python 对象
json.dump()
Python 对象
JSON 文件
OPPO P5226.第2题-最小信号功率 第2题-最小信号功率 - problem_ide - CodeFun2000
核心思路:通过数学公式得到简易表达,注意 $i$ 是变量,所以会有嵌套 max
题意转化
$$
P-|i-c|\ge r_i \rightarrow P\ge r_i+|i-c|
$$
因为
$$
|i-c|=\max(i-c,c-i)
$$
所以
$$
r_i+|i-c|=\max(r_i+i-c,\;r_i-i+c)
$$
要把所有的 $i$ 放到一起考虑
$$
P\ge\max\left(\max_i(r_i+i)-c,\;\max_i(r_i-i)+c\right)
$$
再分别取最大,定义
$$
A=\max_i(r_i+i),\qquad B=\max_i(r_i-i)
$$
整个问题变成找
$$
\min_c \max(A-c,\ B+c)
$$
所以要让两者的最大值尽可能小,最佳位置就是让二者尽量相等
$$
A - c = B+c
$$
得到
$$
c=\frac{A-B}{2}
$$
由于 $c$ 必须是整数,所以最小发射功率为:
$$
\boxed{P_{\min}=\left\lceil\frac{A+B}{2}\right\rceil}
$$
1 2 3 4 5 6 7 8 9 10 11 12 def main (): n = int (input ()) R = list (map (int , input ().split())) A = float ("-inf" ) B = float ("-inf" ) for i,r in enumerate (R): A = max (A, r+i+1 ) B = max (B, r-i-1 ) P = (A+B+1 )//2 print (P) if __name__ == "__main__" : main()
P5221.第2题-监测样本偏离判定 第2题-监测样本偏离判定 - problem_ide - CodeFun2000
核心:了解如何调用 sklearn 实现 PCA
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 import numpy as npimport jsonimport sysfrom sklearn.preprocessing import StandardScalerfrom sklearn.decomposition import PCAdef main (): data = json.loads(sys.stdin.read()) train = data["train" ] test = data["test" ] X = np.array(train, dtype = float ) T = np.array(test, dtype= float ) means = np.nanmean(X, axis = 0 ) row, col = np.where(np.isnan(X)) X[row, col] = means[col] row, col = np.where(np.isnan(T)) T[row, col] = means[col] scaler = StandardScaler() X_scaled = scaler.fit_transform(X) T_scaled = scaler.transform(T) pca = PCA(n_components=0.95 , svd_solver="full" ) pca.fit(X_scaled) X_rebuild = pca.inverse_transform(pca.transform(X_scaled)) T_rebuild = pca.inverse_transform(pca.transform(T_scaled)) train_error = np.sum ((X_scaled - X_rebuild)**2 , axis= 1 ) test_error = np.sum ((T_scaled - T_rebuild)**2 , axis=1 ) threshold = np.percentile(train_error, 95 ) ans = (test_error > threshold).astype(int ).tolist() print (json.dumps(ans)) if __name__ == "__main__" : main()
sklearn 逻辑:
1 2 3 4 5 model = Something(...) # 创建工具 / 设置超参数 model.fit(X) # 从 X 学参数 model.transform(X) # 用学到的参数转换 X model.fit_transform(X) # 先学,再转换 X model.inverse_transform(Z) # 把转换后的数据尽量映射回原来的空间
科大讯飞 P5227.第1题-巡检通道覆盖补点 第1题-巡检通道覆盖补点 - problem_ide - CodeFun2000
核心思路:维护“从 0 开始已经连续覆盖到哪里”,不要混着节点和区间写
把所有已有节点转换成覆盖区间
并裁切到[0, L]
如果一个完全需要新节点覆盖的连续区间长度为
$$
\left\lceil\frac{t}{2D}\right\rceil
$$
向上取整应该在分子加上分母-1
1 (t + 2 * D - 1) // (2 * D)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 def main (): L, k, D = map (int , input ().split()) intervals = [] for _ in range (k): x, c = map (int , input ().split()) left = max (0 , x - c) right = min (L, x + c) intervals.append((left, right)) intervals.sort() cur = 0 ans = 0 width = 2 * D for left, right in intervals: if right <= cur: continue if left > cur: gap = left - cur cnt = (gap + width - 1 ) // width ans += cnt cur += cnt * width if left <= cur: cur = max (cur, right) if cur >= L: break if cur < L: gap = L - cur ans += (gap + width - 1 ) // width print (ans) if __name__ == "__main__" : main()
拼多多 P5211.第1题-平衡队伍 第1题-平衡队伍 - problem_ide - CodeFun2000
核心思路:转化成“最长和为 0 的连续子数组”,并利用前缀和记录最远idx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 def main (): n = int (input ()) s = input () first = {0 :0 } prefix = 0 ans = 0 for i,c in enumerate (s, 1 ): if c == "A" : prefix += 1 else : prefix -= 1 if prefix in first: ans = max (ans, i - first[prefix]) else : first[prefix] = i print (ans) if __name__ == "__main__" : main()
P5212.第2题-评价展示序列 第2题-评价展示序列 - problem_ide - CodeFun2000
核心思路:从左到右构造答案,每一位都尽量放最小的数字,但放之前必须判断“放了它以后,剩下的数还能不能排成合法序列”
需要满足
$$
\max(cnt)\leq \left\lceil\frac n2\right\rceil
$$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 def main (): n = int (input ()) star = list (map (int , input ().split())) cnt = [0 ] * 6 for x in star: cnt[x] +=1 if max (cnt) > (n+1 )//2 : print ("-1" ) return def available (prev, remain ): """ 已经放置了 prev, 判断剩余 remain 个元素能否继续排列。 """ for x in range (1 ,6 ): if x == prev: if cnt[x] > remain - cnt[x]: return False else : if cnt[x] > remain - cnt[x] + 1 : return False return True ans = [] prev = 0 for pos in range (n): for x in range (1 ,6 ): if cnt[x] == 0 : continue if x == prev: continue cnt[x] -= 1 remain = n - pos - 1 if available(x, remain): ans.append(x) prev = x break cnt[x] +=1 print (*ans) if __name__ == "__main__" : main()
P5255.第2题-报文出站判定 第2题-报文出站判定 - problem_ide - CodeFun2000
重点:栈,理解都先往里放
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 def can_queue (u, v ): return u == v def can_stack (u, v ): st = [] j = 0 for c in u: st.append(c) while st and j < len (v) and st[-1 ] == v[j]: st.pop() j+=1 if j == len (v): return True return False def main (): U = input () V = input () is_queue = can_queue(U, V) is_stack = can_stack(U, V) if is_queue: print ("both" ) elif is_stack: print ("stack" ) else : print ("neither" ) if __name__ == "__main__" : main()
P5256.第3题-工单最大收益 第3题-工单最大收益 - problem_ide - CodeFun2000
注意以工单作为编号做dp,初做时以时间为窗口做dp,复杂度太大
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 from bisect import bisect_rightdef main (): n = int (input ()) jobs = [] for _ in range (n): start, end, val =map (int , input ().split()) jobs.append((start, end, val)) jobs.sort(key = lambda x:x[1 ]) dp = [0 ] * (n+1 ) ends = [e for _, e, _ in jobs] for i in range (1 , n+1 ): start, end , val = jobs[i-1 ] j = bisect_right(ends, start, 0 , i-1 ) dp[i] = max ( dp[i-1 ], dp[j]+val ) print (dp[n]) if __name__ == "__main__" : main()
百度 P5216.第2题-最小对冲值 第2题-最小对冲值 - problem_ide - CodeFun2000
二进制整数有一个非常重要的关系
$$
a+b=(a\oplus b)+2(a\&b)
$$
已知
$$
a+b = m
$$
代入恒等式
$$
(a\oplus b)+2(a\&b) = m
$$
得到目标
$$
a\oplus b=m-2(a\&b)
$$
因为 m 值固定,所以求 `a&b` 的最大值
两个数越接近,其二进制高位越容易同时出现 1
如果 m 是偶数,那么答案必定是0
如果 m 是奇数,最接近的拆法就是
$$
m = 2k+1\qquad a=k\quad b=k+1
$$
即
$$
\boxed{\left\lfloor\frac m2\right\rfloor\oplus\left\lceil\frac m2\right\rceil}
$$
P5217.第3题-报文置换归位 第3题-报文置换归位 - problem_ide - CodeFun2000
思路:置换拆成若干个环 → 每个环上的字符构成一个循环字符串 → 求每个循环字符串的最小周期 → 所有最小周期取 LCM
因为 p 是一个排列,所以它一定可以拆成若干个互不相交的 置换环
一次操作,本质上就是让这个环上的字符串循环移动一位
但重要的是不能直接用环长度,因为环上字符有可能相等,有可能在最小周期前已经复原
求一个字符串的最小周期可以使用 KMP 的 prefix function / 前缀函数
对于长度为 L 的字符串 s,设
$$
x=L-\pi[L-1]
$$
$\pi[i]$:对字符串 $s[:i+1]$,从开头取一段、从结尾取一段,最长能有多少个字符完全一样,排除整个字符串本身
如果
$$
L\bmod x=0
$$
那么 $ \text{period}=x$ 否则 $\text{period}=L$
把所有的环找到以后计算每个环的最小周期,然后求最小公倍数 LCM
$$
\boxed{\operatorname{lcm}(a,b)=\frac{a\times b}{\gcd(a,b)}}
$$
利用最大公约数函数 `math.gcd`
1 ans = ans * period // gcd(ans, period)
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 from math import gcdMOD = 10 **9 + 7 def get_period (s ): n = len (s) pi = [0 ] * n for i in range (1 , n): j = pi[i-1 ] while j>0 and s[i]!=s[j]: j = pi[j-1 ] if s[i] == s[j]: j+=1 pi[i] = j period = n - pi[-1 ] if n%period == 0 : return period else : return n def main (): n = int (input ()) u = input ().strip() p = list (map (int , input ().split())) p = [x-1 for x in p] visited = [False ] * n ans =1 for i in range (n): if visited[i]: continue cur = i chars = [] while not visited[cur]: visited[cur] = True chars.append(u[cur]) cur = p[cur] period = get_period(chars) ans = ans * period // gcd(ans, period) print (ans % MOD) if __name__ == "__main__" : main()
抖音 P4808.第1题-最小喷灌范围 第1题-最小喷灌范围 - problem_ide - CodeFun2000
核心思路:从暴力做法优化,遍历覆盖,带二分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 def check (area, n, m, x ): cnt = 0 cover = 0 for i in range (1 ,n+1 ): if i<=cover: continue if area[i-1 ] == 1 : cnt +=1 cover = i+x-1 if cnt > m: return False return True def main (): T = int (input ()) for _ in range (T): n, m = map (int , input ().split()) area = list (map (int , input ().split())) if 1 not in area: print (0 ) continue left = 1 right = n while left<right: mid = (left+right)//2 if check(area, n, m, mid): right = mid else : left = mid+1 print (left) if __name__ == "__main__" : main()