A. 奶牛杀 题面 题目描述贝茜和她的朋友们正在玩奶牛杀。在这款游戏中,贝茜本色出演奶牛,她的 n n n 个朋友扮演猎人。猎人从 1 1 1 到 n n n 编号,第 i i i 个猎人有血量 a i a_i a i 和攻击力 b i b_i b i 。且第 i i i 个猎人瞄准 i m o d n + 1 i \bmod n+1 i mod n + 1 个猎人。当第 i i i 个猎人血量小于等于 0 0 0 时,会立刻向第 i m o d n + 1 i\bmod n+1 i mod n + 1 个猎人开枪,使之血量减少 b i b_i b i 点。如果它也血量变为了小于等于 0 0 0 则也会开枪,有可能造成连锁开枪。
需要注意的是,本游戏并无缩圈环节,若第 i m o d n + 1 i \bmod n+1 i mod n + 1 个猎人已经退出游戏,i i i 号会打空而非向后寻找人开枪。
在奶牛杀中,没有投票环节,只有贝茜每晚上袭击一个猎人,造成 1 1 1 点伤害。她现在想知道最快需要几个晚上才能杀死所有猎人?
输入格式第一行一个正整数 n n n 表示猎人总数。
接下来的 n n n 行,第行包含两个正整数 a i , b i a_i,b_i a i , b i ,分别表示第 i i i 个猎人的血量和攻击力。
输出格式输出一个正整数,表示贝茜最快需要多少个晚上获得胜利。
输入输出样例 样例输入 #13 7 15 2 14 5 3
样例输出 #16
样例解释 #1最佳策略是连续 2 2 2 个晚上攻击猎人 2 2 2 ,其死亡时的射击导致猎人 3 3 3 死亡,猎人 3 3 3 死亡时的射击对猎人 1 1 1 造成3 3 3 点伤害,接下来只需要连续 4 4 4 个晚上攻击猎人 1 1 1 即可。
数据范围与约定对于 10 % 10\% 10% 的数据,保证 n ≤ 10 n\leq 10 n ≤ 10 , 对于另外 10 % 10\% 10% 的数据,保证 n ≤ 100 n\leq 100 n ≤ 100 , 对于另外 20 % 20\% 20% 的数据,保证 n ≤ 1000 n\leq 1000 n ≤ 1000 , 对于另外 20 % 20\% 20% 的数据,保证 b i ≤ a i m o d n + 1 b_i\leq a_{i\ mod\ n+1} b i ≤ a i m o d n + 1 , 对于 100 % 100\% 100% 的数据,保证 n ≤ 3 ∗ 1 0 5 , 1 ≤ a i , b i ≤ 1 0 12 n\leq 3*10^5,1\leq a_i,b_i\leq 10^{12} n ≤ 3 ∗ 1 0 5 , 1 ≤ a i , b i ≤ 1 0 12 。 题意简述给定 n n n 个人,以及其生命值 a i a_i a i ,这 n n n 个人之间的关系构成一个环,每个人死亡时会对下一个人造成 b i b_i b i 的伤害,你可以选择任意数量的人造成任意伤害,求为了使所有人死亡你所需要造成的伤害
思路为了方便,我们把每个人的下一个人记为 n x t i nxt_i n x t i ,上一个人记为 p r e i pre_i p r e i
假设我们从第 k k k 个人开始造成伤害,那么杀掉第一个人所需要的伤害为 a k a_k a k ,对于其余所有人,如果他的上一个人可以直接杀掉他,那么我们就不做干预,否则就另外造成伤害
那么显然以第 k k k 个人开始的所需要的伤害为:
− max { b p r e k − a k , 0 } + a k + ∑ i = 1 n max { b p r e i − a i , 0 } -\max{ \{b_{pre_k} - a_k, 0\} } + a_k+ \sum \limits_{i = 1}^{n} \max{ \{b_{pre_i} - a_i, 0\} } − max { b p r e k − a k , 0 } + a k + i = 1 ∑ n max { b p r e i − a i , 0 }
那么计算出 s u m = ∑ i = 1 n max { b p r e i − a i , 0 } sum = \sum \limits_{i = 1}^{n} \max{ \{b_{pre_i} - a_i, 0\} } s u m = i = 1 ∑ n max { b p r e i − a i , 0 } ,枚举每个位置更新答案即可
总的时间复杂度为 O ( n ) O(n) O ( n )
代码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 #include <bits/stdc++.h> namespace solution{ typedef long long LL; const int MAXN = 3e5 + 5 ; const LL INF = 0x3f3f3f3f3f3f3f3f LL; int n; LL sum = 0 ; LL ans = INF; LL a[MAXN], b[MAXN], c[MAXN]; int main () { freopen ("doge.in" , "r" , stdin); freopen ("doge.out" , "w" , stdout); scanf ("%d" , &n); for (int i = 1 ; i <= n; i++) { scanf ("%lld%lld" , &a[i], &b[i]); } for (int i = 1 ; i <= n; i++) { c[i % n + 1 ] = std::max (0LL , a[i % n + 1 ] - b[i]); sum += c[i % n + 1 ]; } for (int i = 1 ; i <= n; i++) { ans = std::min (ans, sum - c[i] + a[i]); } printf ("%lld\n" , ans); return 0 ; } } int main () { solution::main (); return 0 ; }
B. 备餐 题面 题目描述约翰要给他的奶牛们备餐,有 n n n 种食物,每种食物有满意度 a i a_i a i 。约翰将准备食物的一个非空子序列给奶牛。
奶牛们对食物的要求也很高,他们要求从准备的食物中任选两个计算他们满意度的异或,如果小于他们的忍耐度 x x x 就会生气。
约翰想问问你,在所有 2 n − 1 2^n-1 2 n − 1 个非空子序列中,有多少种序列满足,“任选两种食物,满意度的异或和大于等于奶牛的忍耐度 x x x ”?你需要输出方案数模 998244353 998244353 998244353 之后的结果。
如果子序列只有一个元素,约翰认为一定是合法的。
输入格式第一行包含两个非负整数 n , x n,x n , x 表示食物的种类数和奶牛们的忍耐度。
第二行包含 n n n 个非负整数 a 1 , a 2 , . . . a n a_1,a_2,...a_n a 1 , a 2 , ... a n 表示每种食物的满意度。
输出格式输出一个非负整数,表示方案数模 998244353 998244353 998244353 的结果。
输入输出样例 样例输入 #13 0 0 1 2
样例输出 #17
样例解释 #1所有的 2 3 − 1 2^3-1 2 3 − 1 个非空子序列都满足条件
样例输入 #23 2 0 1 2
样例输出 #25
样例解释 #2由于 0 ⨁ 1 = 1 < 2 0 \bigoplus 1=1<2 0 ⨁ 1 = 1 < 2 ,子序列 { 0 , 1 } \{0,1\} { 0 , 1 } 和子序列 { 0 , 1 , 2 } \{0, 1, 2\} { 0 , 1 , 2 } 不满足条件。
样例输入 #37 4 11 5 5 8 3 1 3
样例输出 #335
样例解释 #3不保证 a i a_i a i 互不相同,选取不同的 5 5 5 或 3 3 3 ,被认为是不同的方案。
数据范围与约定对于 100 % 100\% 100% 的数据,保证 1 ≤ n ≤ 3 ∗ 1 0 5 1\leq n \leq 3*10^5 1 ≤ n ≤ 3 ∗ 1 0 5 。0 ≤ a i , x < 2 60 0\leq a_i,x< 2^{60} 0 ≤ a i , x < 2 60 。 C. 约翰:奶牛杀手 题面 题目描述约翰最近迷恋上了《只狼:影逝二度》,于是他决定拿奶牛试试手。
具体来说,有 n n n 个奶牛站在一个数轴上,每个奶牛有一个位置 x i x_i x i ,还有一个警戒范围 [ l i , r i ] [l_i,r_i] [ l i , r i ] 。
刚开始所有奶牛都是未警戒的状态。约翰可以偷袭并瞬间杀死一个未警戒状态的奶牛 i i i ,但此时所有 x i ∈ [ l j , r j ] x_i\in[l_j,r_j] x i ∈ [ l j , r j ] 的奶牛j j j 都会进入警戒状态并前来杀死小W,即满足i的位置位于j的警戒范围内的j。其他奶牛则会保持未警戒状态。
约翰有一次复活机会,复活后仍然活着的奶牛会恢复到未警戒状态和原来的位置。但是如果复活后偷袭被别的奶牛再次被发现就会失败。
约翰有 T T T 个农场,他想问问你能否只使用偷袭和复活来通关每张地图。进入每张地图时复活次数会重置为1。
输入格式输入的第一行包含一个正整数 T T T ,表示地图总数。
接下来连续输入 T T T 张地图的信息。
每张地图的第一行包含一个正整数 n n n ,表示这张地图中的奶牛总数。
此后的 n n n 行,每行包含三个正整数 x i , l i , r i x_i, l_i, r_i x i , l i , r i ,表示第 i i i 头奶牛的位置和警戒范围。保证奶牛按照坐标严格升序给出,即 x 1 < x 2 < . . . < x n x_1 < x_2 < ... < x_n x 1 < x 2 < ... < x n 。
输出格式输出 T T T 行,每行包含一个字符串 Yes
或 No
,分别表示约翰是否可以通过这张地图。
输入输出样例 样例输入 #12 4 3 1 5 6 2 10 7 4 10 9 8 11 3 1 1 3 2 1 3 3 1 3
样例输出 #1Yes No
样例解释 #1对于第一张地图,约翰可以首先对第二个奶牛(位置为 6)发动偷袭,并会被第三个奶牛杀死。在复生后,他可以按照三,一,四的顺序分别杀死剩余的三个奶牛,并且不会引起敌人的警觉。 对于第二张地图,可以发现无论如何安排顺序,约翰都被顺序中最后 的那个敌人杀死两次,用完所有的复生机会。
数据范围与约定对于 100 % 100\% 100% 的数据,保证 1 ≤ T ≤ 1 0 5 , 1 ≤ n ≤ 1 0 6 , ∑ n ≤ 3 ∗ 1 0 6 , 1 ≤ l i ≤ x i ≤ r i ≤ 1 0 9 , 1 ≤ x 1 < x 2 < . . . < x n ≤ 1 0 9 1\leq T\leq 10^5,1\leq n \leq 10^6,\sum n\leq 3*10^6,1\leq l_i\leq x_i\leq r_i\leq 10^9,1\leq x_1<x_2<...<x_n\leq 10^9 1 ≤ T ≤ 1 0 5 , 1 ≤ n ≤ 1 0 6 , ∑ n ≤ 3 ∗ 1 0 6 , 1 ≤ l i ≤ x i ≤ r i ≤ 1 0 9 , 1 ≤ x 1 < x 2 < ... < x n ≤ 1 0 9 。
题意简述给定 n n n 个区间,每个区间包含三个信息:x i , l i , r i x_i, l_i, r_i x i , l i , r i ,求判断能否在删除某个区间之后,可以通过每次选择一个“ x i x_i x i 不属于任何其他未删除的区间的 l j , r j l_j, r_j l j , r j 的区间”删除掉,使得所有区间最后都被删除
暴力做法简化题意,可以通过相互包含的关系建出一张有向图,图上有环时则无法处理,只能将某个区间删除掉
那么可以通过枚举环上的点删除,拓扑排序判断图中是否还有其他环的方法来解决,时间复杂度为 O ( n 3 ) O(n ^ 3) O ( n 3 )
可以发现如下性质:图中如果存在环,那么必定存在二元环,
以三元环为例,假设图中有三元环 a , b , c a, b, c a , b , c ,不妨设 x a < x b < x c x_a < x_b < x_c x a < x b < x c ,显然 b b b 可以在 a a a 的区间内,c c c 可以在 b b b 的区间内,又因为构成环,那么 a a a 或 b b b 必定有一个在 c c c 的区间内,显然无论哪种情况,图中都有二元环,故命题得证
那么现在的问题就变成了在图中找二元环的问题
首先可以在图中找出任意一对二元环,对环上的两个点枚举删除,判断图中是否还有其他二元环
判断二元环时可以从左向右枚举每个点,同时维护一个栈,栈中的元素从栈底到栈顶 x x x 递增,r r r 递减,x x x 递增保证了栈中元素最可能被包含在其他区间中,r r r 递减保证了区间中的元素最可能包含其他元素,那么对于每个当前枚举到的元素 i i i ,一直弹出栈中元素,直到栈中元素的 r r r 大于 i i i 的 r r r 为止,对于弹出的每个元素以及最后的栈顶,判断其与 i i i 是否构成二元环,如果枚举完了都没有找到,说明图中不存在二元环 ,也就说明原图为有向无环图
下面考虑证明正确性
假设图中存在二元环 a , b a, b a , b ,不妨设 a x < b x a_x < b_x a x < b x ,那么一定有 a l ≤ b x ≤ a r a_l \le b_x \le a_r a l ≤ b x ≤ a r ,分两以下几种情况讨论:
枚举到 b b b 时 a a a 未被弹出栈, 此时要么枚举到 b b b 时与 a a a 进行判断,发现 a , b a, b a , b 的环,要么枚举到后边某个位置 c c c 时,发现一个更大的环 枚举到 b b b 时 a a a 已经出栈,说明在前边某个位置 c c c ,a a a 已经和 c c c 构成环 故若图中有环,那么该算法一定可以找到
代码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 60 61 62 63 64 65 66 67 68 69 #include <bits/stdc++.h> namespace solution{ typedef long long LL; const int MAXN = 3e6 + 5 ; int t; LL n; LL a[MAXN]; struct Node { LL l, x, r; }; Node node[MAXN]; auto find (int pos) { std::stack<int > stk; for (int i = 1 ; i <= n; i++) { if (i == pos) { continue ; } while (!stk.empty ()) { int u = stk.top (); if (node[i].l <= node[u].x && node[u].x <= node[i].r && node[u].l <= node[i].x && node[i].x <= node[u].r) { return std::make_pair (i, u); } if (node[u].r > node[i].r) { break ; } stk.pop (); } stk.push (i); } return std::make_pair (0 , 0 ); } int main () { freopen ("sekiro.in" , "r" , stdin); freopen ("sekiro.out" , "w" , stdout); scanf ("%d" , &t); while (t--) { scanf ("%lld" , &n); for (int i = 1 ; i <= n; i++) { scanf ("%lld%lld%lld" , &node[i].x, &node[i].l, &node[i].r); } auto t = find (0 ); if (t == std::make_pair (0 , 0 ) || find (t.first) == std::make_pair (0 , 0 ) || find (t.second) == std::make_pair (0 , 0 )) { puts ("Yes" ); } else { puts ("No" ); } } return 0 ; } } int main () { solution::main (); return 0 ; }