先给每一圈赋一个权重dis
算该点具体在那一个圈权值多少 就用dis[min(min(i, j), min(n-i, n-j))]
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> using namespace std;using ll = long long ;using PII = pair<int , int >;#define pb push_back #define all(x) (x).begin(), (x).end() #define fi first #define se second #define endl '\n' #define debug(x) \ { \ cerr << #x << " = " << x << endl; \ } #define debugfull(x) \ { \ cerr << #x << " = " << x << " (line " << __LINE__ << ")" << endl; \ } int dis[5 ] = {1 , 2 , 3 , 4 , 5 };void solve () { vector<string> nums; int n = 10 ; while (n--) { string s; cin >> s; nums.emplace_back (s); } ll res = 0 ; for (int i = 0 ; i < 10 ; i++) { for (int j = 0 ; j < 10 ; j++) { if (nums[i][j] == '.' ) continue ; else { res += dis[min (min (i, j), min (9 - i, 9 - j))]; } } } cout << res << endl; }int main () { ios::sync_with_stdio (0 ); cin.tie (0 ); int T; cin >> T; while (T--) { solve (); } return 0 ; }
赛时调了半天没调出来,寄,害的F也没调出来/kk
二分的板子没问题啊,主要是r的范围错了,r是要超过x很多的,而且还要同时注意 开ll 如果太大的话mid的范围也要注意
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 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 #include <bits/stdc++.h> using namespace std;using ll = long long ;using PII = pair<int , int >;#define pb push_back #define all(x) (x).begin(), (x).end() #define fi first #define se second #define endl '\n' #define debug(x) \ { \ cerr << #x << " = " << x << endl; \ } #define debugfull(x) \ { \ cerr << #x << " = " << x << " (line " << __LINE__ << ")" << endl; \ } const int N = 2e5 + 10 ;int nums[N];int n, m;bool check (int mid) { ll res = 0 ; for (int i = 0 ; i < n; i++) { if (mid - nums[i] >= 0 ) res += (mid - nums[i]); if (res > m) return false ; } return true ; }void solve () { cin >> n >> m; memset (nums, 0 , sizeof (nums)); ll l = 1 , r = 2e9 + 1 ; for (int i = 0 ; i < n; i++) { cin >> nums[i]; } int res = 1 , mid; while (l <= r) { mid = (l + r) >> 1 ; if (check (mid)) { res = mid; l = mid + 1 ; } else { r = mid - 1 ; } } cout << res << endl; }int main () { ios::sync_with_stdio (0 ); cin.tie (0 ); int T; cin >> T; while (T--) { solve (); } return 0 ; }
AB->BC BA->CB
那么只要有B就可以把所有的A都消除掉(只能消除一边)分几种情况来讨论 首先B在首或尾的时候如果中间没有B 可以全部消除完
如果有两个B连在一起的话只可能是B..BB…B 中间的..可能是A也可能是B 都可以把所有A消除(左边的B消掉左边的A 右边的B消除右边的B
如果没有两个B连在一起的话那么中间必然会有空缺 AABABAA那么只能消掉三个中的两个 所以最后要减去A最少的一段
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 70 71 72 73 74 75 #include <bits/stdc++.h> using namespace std;using ll = long long ;using PII = pair<int , int >;#define pb push_back #define all(x) (x).begin(), (x).end() #define fi first #define se second #define endl '\n' #define debug(x) \ { \ cerr << #x << " = " << x << endl; \ } #define debugfull(x) \ { \ cerr << #x << " = " << x << " (line " << __LINE__ << ")" << endl; \ } int main () { ios::sync_with_stdio (0 ); cin.tie (0 ); int n; cin >> n; while (n--) { string s; cin >> s; bool flag = false ; ll sum = 0 ; int n = s.size (); int cnt = 0 ; int minn = 1e9 + 7 ; if (s[0 ] == 'B' || s[n - 1 ] == 'B' ) flag = true ; for (int i = 0 ; i < n; i++) { if (s[i] == 'A' ) sum++, cnt++; else if (s[i] == 'B' ) { minn = min (minn, cnt); cnt = 0 ; if (i + 1 < n && s[i + 1 ] == 'B' ) flag = true ; } } minn = min (minn, cnt); if (flag) { cout << sum << endl; } else { if (minn != 1e9 + 7 ) cout << sum - minn << endl; else cout << 0 << endl; } } return 0 ; }
寻找基环树(套路)因为这个题不仅要判断环 而且需要储存
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 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 #include <bits/stdc++.h> using namespace std;using ll = long long ;using PII = pair<int , int >;#define pb push_back #define all(x) (x).begin(), (x).end() #define fi first #define se second #define endl '\n' #define debug(x) \ { \ cerr << #x << " = " << x << endl; \ } #define debugfull(x) \ { \ cerr << #x << " = " << x << " (line " << __LINE__ << ")" << endl; \ } void solve () { int n, a, b; cin >> n >> a >> b; vector<vector<int >> graph (n + 1 ); for (int i = 0 ; i < n; i++) { int u, v; cin >> u >> v; graph[u].pb (v); graph[v].pb (u); } if (a == b) { cout << "NO" << endl; return ; } vector<int > incircle (n + 1 , 0 ) , vis (n + 1 , 0 ) , pre (n + 1 , 0 ) ; bool ok = false ; function<void (int , int )> dfs = [&](int u, int fa) { for (int v : graph[u]) { if (ok) return ; if (v == fa) continue ; if (vis[v]) { ok = true ; incircle[v] = 1 ; int x = u; do { incircle[x] = 1 ; x = pre[x]; } while (x != v); } else { vis[v] = 1 ; pre[v] = u; dfs (v, u); } } }; vis[1 ] = 1 ; dfs (1 , 0 ); if (incircle[b]) { cout << "YES" << endl; return ; } int goal = -1 , gdis = -1 ; queue<PII> q; vis.assign (n + 1 , 0 ); q.push ({b, 0 }); vis[b] = 1 ; while (!q.empty ()) { int u = q.front ().first; int dis = q.front ().second; q.pop (); for (int v : graph[u]) { if (vis[v]) continue ; if (incircle[v]) { goal = v; gdis = dis + 1 ; goto end; } else { q.push ({v, dis + 1 }); vis[v] = 1 ; } } } end:; if (goal == a) { cout << "NO" << endl; return ; } while (!q.empty ()) { q.pop (); } int tdis = -1 ; vis.assign (n + 1 , 0 ); q.push ({a, 0 }); vis[a] = 1 ; while (!q.empty ()) { int u = q.front ().first; int dis = q.front ().second; q.pop (); for (int v : graph[u]) { if (vis[v]) continue ; if (v == goal) { tdis = dis + 1 ; if (tdis <= gdis) cout << "NO" << endl; else cout << "YES" << endl; return ; } else { q.push ({v, dis + 1 }); vis[v] = 1 ; } } } }int main () { ios::sync_with_stdio (0 ); cin.tie (0 ); int T; cin >> T; while (T--) { solve (); } return 0 ; }
一位数 两位数 三位数 分别表达 而四位数及以上时 不需要 因为1000 可以被8 整除 而所有的四位数 如1000 2000 3000 等都可以被8整除 而所有的四位数都可以被表示为 1000 * k + x (x为一位数或者两位数 或者三位数 ) 更高位的以此类推 所以只需要枚举1 2 3 位数
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 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 #include <bits/stdc++.h> using namespace std;using ll = long long ;using PII = pair<int , int >;#define pb push_back #define all(x) (x).begin(), (x).end() #define fi first #define se second #define endl '\n' #define debug(x) \ { \ cerr << #x << " = " << x << endl; \ } #define debugfull(x) \ { \ cerr << #x << " = " << x << " (line " << __LINE__ << ")" << endl; \ } int main () { ios::sync_with_stdio (0 ); cin.tie (0 ); string s; cin >> s; int n = s.size (); for (int i = 0 ; i < n; i++) { if (s[i] == '8' ) { cout << "YES" << endl; cout << "8" << endl; return 0 ; } if (s[i] == '0' ) { cout << "YES" << endl; cout << "0" << endl; return 0 ; } } for (int i = 0 ; i < n; i++) { for (int j = i + 1 ; j < n; j++) { int a = ((s[i] - '0' ) * 10 + s[j] - '0' ); if (a % 8 == 0 ) { cout << "YES" << endl; cout << a << endl; return 0 ; } } } for (int i = 0 ; i < n; i++) { for (int j = i + 1 ; j < n; j++) { for (int k = j + 1 ; k < n; k++) { int a = ((s[i] - '0' ) * 100 + (s[j] - '0' ) * 10 + s[k] - '0' ); if (a % 8 == 0 ) { cout << "YES" << endl; cout << a << endl; return 0 ; } } } } cout << "NO" << endl; return 0 ; }
给出区间 然后反转 可以用差分 当这个下标被旋转奇数次的时候就需要旋转 被旋转偶数次的时候 就相当于没动 不用旋转
每次旋转要找到唯一一个i 使得a[i] <= x && b[i] >= x 然后旋转a[i] b[i] 的元素
可以用cnt(类似差分数组)记录x出现的次数 并且不需要根据x寻找第二行所说的那个区间 而是遍历区间 找到这个区间的x
遍历区间 然后取出子串 从left到mid依次与right到mid交换 (根据sum的奇偶来判断)sum就是当前位置和对称位被交换次数之和(累计 因为是差分)然后输出子串
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 70 71 72 73 74 75 76 77 78 79 using namespace std; using ll = long long; using PII = pair<int , int >; { \ cerr << } { \ cerr << } /*-------------------------------------------*/ void solve() { int n, k; string s; cin >> n >> k; cin >> s; vector<int > a(k), b(k); vector<int > cnt(n); for (int i = 0 ; i < k; i++) cin >> a[i], a[i]--; for (int i = 0 ; i < k; i++) cin >> b[i], b[i]--; int q; cin >> q; for (int i = 0 ; i < q; i++) { int x; cin >> x; cnt[x - 1 ]++; } for (int i = 0 ; i < k; i++) { string s1 = s.substr(a[i], b[i] - a[i] + 1 ); int sum = 0 ; int l = a[i]; int r = b[i]; for (int j = l; j <= (l + r) / 2 ; j++) { sum += cnt[j] + cnt[r - j + l]; if (sum % 2 ) swap(s1[j - l], s1[r - j]); } cout << s1; } cout << endl; }int main() { // clock_t st = clock(), ed; ios::sync_with_stdio(0 ); cin.tie(0 ); // cout << setprecision(15 ) << fixed; int T; cin >> T; while (T--) solve(); // ed = clock(); // double endtime = (double)(ed - st) / CLOCKS_PER_SEC; // cout << "Total time: " << endtime << endl; return 0 ; }
按位与的结果只能越来越小 因此要求最小的按位与的子数组的和 就是全部与在一起的和 就是最小的 但是又特殊情况 就是 当全部的与为0时 可能中间有一部分已经为0了 这样就可以拆成很多个与为0的子数组 如果不为0 那必然整个数组的与就是最小值
1 2 3 4 5 6 7 8 9 10 11 12 13 class Solution : def maxSubarrays (self, nums: List [int ] ) -> int : t = nums[0 ] n = len (nums) cnt = 0 for i in range (1 , n): if t == 0 : cnt += 1 t = nums[i] t&=nums[i] if t == 0 : cnt += 1 return cnt if cnt != 0 else 1
由于题目说了 整棵树所有结点的和一定为k的倍数 那么从中取出一棵节点和为k的倍速的子树 剩下的部分的结点和一定也为k的倍数
因此可以自底向上递归 每次找到一棵节点和为k的倍数的子树 就直接加入答案
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 class Solution : def maxKDivisibleComponents (self, n: int , edges: List [List [int ]], values: List [int ], k: int ) -> int : self.link = [[] for _ in range (n)] for s, e in edges: self.link[s].append(e) self.link[e].append(s) self.res = 1 self.dfs(0 , -1 , values, k) return self.res def dfs (self, node, parent, values, k ): node_sum = values[node] for child in self.link[node]: if child == parent: continue child_sum = dfs(child, node, values, k) if child_sum % k == 0 : self.res += 1 else : node_sum += child_sum return node_sum
遍历j 算出j的前缀的最大值和j的后缀的最大值 因为求得是(nums[i] - nums[j]) * nums[k] 所以i k要尽量大
后缀就是从n - 1往前 求出每一个j值所对应的最大后缀 前缀同理
最后直接计算
1 2 3 4 5 6 7 8 9 10 11 12 class Solution : def maximumTripletValue (self, nums: List [int ] ) -> int : n = len (nums) surmax = [-1 ] * (n + 1 ) for i in range (n - 1 , -1 , -1 ): surmax[i] = max (surmax[i + 1 ], nums[i]) premax = nums[0 ] ans = 0 for i in range (n - 1 ): ans = max (ans, (surmax[i + 1 ] * (premax - nums[i]))) premax = max (premax, nums[i]) return ans
滑动窗口
子数组是连续的 要求最短的就是先看看 能凑成几个完整的原序列 然后再两个序列间 凑出剩余的
剩余的就用滑动窗口来算
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Solution : def minSizeSubarray (self, nums: List [int ], target: int ) -> int : n = len (nums) total = sum (nums) nums = nums + nums x = target // total target %= total s = l = 0 ret = 10 ** 9 for i in range (n * 2 ): s += nums[i] while s > target: s -= nums[l] l += 1 if s == target: ret = min (ret, i - l + 1 ) return ret + x * n
O(n^2) 首先 1的个数的奇偶不同就不能变成一样的 返回-1
用dfs计算加上@cache变为记忆化搜索
每次变都是两个一起变 操作1 第一个变的时候就记录这次变化的消耗 然后另一个就相当于可以免费变化 记录免费变化的次数
操作2 不能像操作1那样在任意位置变 而是 只要用了操作2 必定是连续的两个变
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 class Solution : def minOperations (self, s1: str , s2: str , x: int ) -> int : if s1.count('1' ) % 2 != s2.count('1' ) % 2 : return -1 n = len (s1) @cache def dfs (i: int , j: int , pre_rever: bool ) -> int : if i == n: return inf if j or pre_rever else 0 if s1[i] != s2[i] and pre_rever: return dfs(i + 1 , j, False ) if s1[i] == s2[i] and not pre_rever: return dfs(i + 1 , j, False ) res = min (dfs(i + 1 , j + 1 , False ) + x, dfs(i + 1 , j, True ) + 1 ) if j: res = min (res, dfs(i + 1 , j - 1 , pre_rever)) return res return dfs(0 , 0 , False )
O(n) dp做法
把所有需要变的位置先写出来 然后每次消除 通过操作1 每次消除一个 消耗x/2(最后必定是可以消完的因为不行的情况已经返回-1了)或者用操作2 每次消除两个 比如1,4位置需要变化 那就需要3次操作12 23 34 这样 需要消耗 p[i] - p[i - 1]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution : def minOperations (self, s1: str , s2: str , x: int ) -> int : if s1 == s2: return 0 p = [i for i, (x, y) in enumerate (zip (s1, s2)) if x != y] if len (p) % 2 : return -1 m = len (p) @cache def dfs (i: int ) -> int : if i == -1 : return 0 if i == -2 : return inf return min (dfs(i - 1 ) + x, dfs(i - 2 ) + (p[i] - p[i - 1 ]) * 2 ) return dfs(m - 1 ) // 2
再翻译成递推 dfs(i) -> f[i] 注意翻译的时候 i - 1和i - 2 如果是f[i - 1] 和 f[i - 2] 会导致最后 i == -1 和i == -2 无法表示 所以 每个下标加上2
1 2 3 4 5 6 7 8 9 10 class Solution : def minOperations (self, s1: str , s2: str , x: int ) -> int : f = [0 ] * (m + 1 ) f[0 ] = 0 f[1 ] = x for i in range (1 , m): new_f = min (f[i] + x, f[i - 1 ] + (p[i] - p[i - 1 ]) * 2 ) f[0 ] = f[1 ] f[1 ] = new_f return f[m] // 2
然后空间优化
1 2 3 4 5 6 class Solution : def minOperations (self, s1: str , s2: str , x: int ) -> int : f0, f1 = 0 , x for i in range (1 , m): f0, f1 = f1, min (f1 + x, f0 + (p[i] - p[i - 1 ]) * 2 ) return f1 // 2
与 越与越小 或越或越大 而x^y + y ^ 2 < (x - d)^2 + (y + d)^2 所以 要尽量做或操作 直到最大
用位运算思考 先记录所有数每个比特位上有多少个1 然后构造尽量大的数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution : def maxSum (self, nums: List [int ], k: int ) -> int : m = max (nums).bit_length() cnt = [0 ] * m for x in nums: for i in range (m): cnt[i] += x >> i & 1 ans = 0 for _ in range (k): x = 0 for i in range (m): if cnt[i]: cnt[i] -= 1 x |= 1 << i ans += x * x return ans % (10 ** 9 + 7 )
前后缀优化
类似的还有238. 除自身以外数组的乘积 - 力扣(LeetCode)
不能用乘积全部乘起来再除的方法 因为首先可能有0的情况 会导致错误 然后就是复杂度太高了
虽然说没有写循环 但是 乘积是高精度乘法 复杂度非常高所以会超时
同理 在每次计算前后缀的时候也需要取模防止数据过大超时
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Solution : def constructProductMatrix (self, grid: List [List [int ]] ) -> List [List [int ]]: pre = suf = 1 m = len (grid) n = len (grid[0 ]) ans = [[0 ] * n for i in range (m)] mod = 12345 for i in range (m): for j in range (n): ans[i][j] = pre % mod pre = pre * grid[i][j] % mod for i in range (m - 1 , -1 , -1 ): for j in range (n - 1 , -1 , -1 ): ans[i][j] = ans[i][j] * suf % mod suf = suf * grid[i][j] % mod return ans
这种题目 下标差 然后再找满足另一个条件的 就需要 储存前缀(或后缀)的最大值和最小值
类似于股票的第一题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Solution : def findIndices (self, nums: List [int ], indexDifference: int , valueDifference: int ) -> List [int ]: n = len (nums) max_idx = 0 min_idx = 0 for i in range (indexDifference, n): j = i - indexDifference if nums[j] > nums[max_idx]: max_idx = j elif nums[j] < nums[min_idx]: min_idx = j if abs (nums[i] - nums[max_idx]) >= valueDifference: return [i, max_idx] if abs (nums[i] - nums[min_idx]) >= valueDifference: return [i, min_idx] return [-1 , -1 ]
100077. 最长相邻不相等子序列 II - 力扣(LeetCode)
滑动窗口
一开始写的时候 出了好多错ww 下标什么的 while循环的条件带不带等号 还有最后更新忘记判断字典序
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 class Solution : def shortestBeautifulSubstring (self, s: str , k: int ) -> str : n = len (s) ans = "" l = 0 cnt = 0 i = 0 for i in range (n): if s[i] == '1' : cnt += 1 while cnt > k: if s[l] == '1' : cnt -= 1 l += 1 while l < n and s[l] == '0' : l += 1 if cnt == k: if len (ans) == 0 : ans = s[l:i + 1 ] if i - l + 1 < len (ans): ans = s[l: i + 1 ] elif i - l + 1 == len (ans): if s[l: i + 1 ] < ans: ans = s[l:i + 1 ] return ans
思路是枚举每一个串看他们是否可以分成符合要求的子串
主要分成三个部分 首先就是求 一个子字符串变成半回文串的最小修改次数
需要先预处理出每个长度n的真因子
然后用modify数组来存储每个子字符串的最少修改次数
最后用划分DP来求整个串需要的最少修改次数
dfs(i, j ) 表示把s[0]到s[j] 的字符串划分成i + 1 个子字符串
i 表示还需要分割的次数 i + 1 表示切出来i + 1段
j表示 s[0] ~ s[j]为当前需要切割的部分 (右端点)
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 MX = 201 divisors = [[] for _ in range (MX)]for i in range (1 , MX): for j in range (i * 2 , MX, i): divisors[j].append(i)def get_modify (s:str ) -> int : n = len (s) ans = inf for d in divisors[n]: ret = 0 for i0 in range (d): i, j = i0, n - d + i0 while i < j: ret += s[i] != s[j] i += d j -= d ans = min (ans, ret) return ansclass Solution : def minimumChanges (self, s: str , k: int ) -> int : """ 划分型DP dfs(i, j) i 为 剩余需要分割的个数 那么i + 1 就是切出来的子串的个数 j s[0] ~ s[j] 为当前需要切割的部分 返回修改最少的次数 枚举当前这一段的左端点 L的最小值就是2i 因为 剩下i段要切 每段至少是2(因为1<=d<=len len至少是2) L的最大值为j - 1 设modify[i][j] 为s[i] ~ s[j]最小修改次数 dfs(i, j) = dfs(i - 1, L - 1) + modify[i][j] 终点 i = 0 return modify[0][j] 入口dfs(k - 1, n - 1) """ n = len (s) modify = [[0 ] * n for _ in range (n)] for left in range (n - 1 ): for right in range (left + 1 , n): modify[left][right] = get_modify(s[left:right + 1 ]) @cache def dfs (i, j ): if i == 0 : return modify[0 ][j] ret = inf for L in range (i * 2 , j): ret = min (ret, dfs(i - 1 , L - 1 ) + modify[L][j]) return ret return dfs(k - 1 , n - 1 )
首先思路就错了。。其实是从大(最少出现次数)到小(1) 枚举最小分割的k 一旦满足要求就可以直接返回 而不是先从最小出现次数 计算不对之后 再去拆分每一个数。。因为只要不是k 和k + 1 就不行 k - 1 会与k + 1 冲突
为什么q < r 的时候不行呢 因为 k = 10的时候 比如30分成3个10 可以31 分成10 10 11 ;32 分成10 11 11 ;33分成11 11 11 ;但是到了34 r = 4 q = 3 此时不能把r均摊到q上 所以说这种分法是不行的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution : def minGroupsForValidAssignment (self, nums: List [int ] ) -> int : nums = Counter(nums) m = min (nums.values()) for i in range (m, 0 , -1 ): ans = 0 for v in nums.values(): q, r = divmod (v, i) if q < r: ans = 0 break else : ans += math.ceil(v / (i + 1 )) else : return ans
求出前缀的最小值 后缀的最小值
然后遍历每个i 如果是山状的 取i i-1的最小值 i + 1 的最小值即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution : def minimumSum (self, nums: List [int ] ) -> int : n = len (nums) left_min = [0 ] * n left_min[0 ] = nums[0 ] right_min = [0 ] * n right_min[-1 ] = nums[-1 ] for i in range (1 , n): left_min[i] = min (left_min[i - 1 ], nums[i]) for i in range (n - 2 , -1 , -1 ): right_min[i] = min (right_min[i + 1 ], nums[i]) ret = inf for i in range (1 , n - 1 ): if nums[i] > left_min[i - 1 ] and nums[i] > right_min[i + 1 ]: ret = min (ret, nums[i] + left_min[i - 1 ] + right_min[i + 1 ]) return -1 if ret == inf else ret
容器multiset Problem - D - Codeforces
用multiset可以自动排序 并且存储多个重复的数
注意erase的时候 要用s.erase(s.lower_bound(x))不然会删掉所有的x
本题只需要有一个不相交就行 那也就是 最大的left 和最小的right比较
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 70 71 72 #include <bits/stdc++.h> using namespace std;using ll = long long ;using PII = pair<int , int >;#define pb push_back #define all(x) (x).begin(), (x).end() #define fi first #define se second #define endl '\n' #define debug(x) \ { \ cerr << #x << " = " << x << endl; \ } #define debugfull(x) \ { \ cerr << #x << " = " << x << " (line " << __LINE__ << ")" << endl; \ } multiset<int > s1, s2;void solve () { int l, r; char c; cin >> c >> l >> r; if (c == '+' ) { s1.insert (l); s2.insert (r); } else { s1.erase (s1.lower_bound (l)); s2.erase (s2.lower_bound (r)); } if (s1.empty ()) { cout << "NO" << endl; return ; } auto s = s1.end (), e = s2.begin (); s--; if (*s > *e) { cout << "YES" << endl; } else cout << "NO" << endl; }int main () { ios::sync_with_stdio (0 ); cin.tie (0 ); int T; cin >> T; while (T--) solve (); return 0 ; }
模拟 每次循环比较两个位置的值 然后把小的数变成大的数(题目要求只能增大)计算出差值就是一共要走的步数 并且直接将两个位置的值都修改为较大的值(表示变换了
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 70 71 72 73 74 75 76 #include <bits/stdc++.h> using namespace std;using ll = long long ;using PII = pair<int , int >;#define pb push_back #define all(x) (x).begin(), (x).end() #define fi first #define se second #define endl '\n' #define debug(x) \ { \ cerr << #x << " = " << x << endl; \ } #define debugfull(x) \ { \ cerr << #x << " = " << x << " (line " << __LINE__ << ")" << endl; \ } void solve () { int n; cin >> n; vector<vector<char >> v (n + 5 , vector <char >(n + 5 )); for (int i = 1 ; i <= n; i++) { for (int j = 1 ; j <= n; j++) { cin >> v[i][j]; } } ll ans = 0 ; while (true ) { ll ii = 1 , jj = 1 ; ll tot = 0 ; for (int col = n; col >= 1 ; col--) { for (int row = 1 ; row <= n; row++) { tot += abs (v[ii][jj] - v[row][col]); ans += abs (v[ii][jj] - v[row][col]); v[row][col] = max (v[ii][jj], v[row][col]); v[ii][jj] = max (v[ii][jj], v[row][col]); jj++; } ii++; jj = 1 ; } if (!tot) break ; } cout << ans << endl; }int main () { ios::sync_with_stdio (0 ); cin.tie (0 ); int T; cin >> T; while (T--) solve (); return 0 ; }
n个数 能不能最后变成相同的n个数 注意到 x / x 最终的乘积是不变的 所以可以算出每个数的因子 这些因子乘起来 就是总乘积 然后除了1以外 看看这些因子是否能被n整除 比如 3个5 6个8 肯定是能被分成3个一样的数的 5 * (2 8) 用哈希表记录每个因数的个数
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 70 71 72 73 74 #include <bits/stdc++.h> using namespace std;using ll = long long ;using PII = pair<int , int >;#define pb push_back #define all(x) (x).begin(), (x).end() #define fi first #define se second #define endl '\n' #define debug(x) \ { \ cerr << #x << " = " << x << endl; \ } #define debugfull(x) \ { \ cerr << #x << " = " << x << " (line " << __LINE__ << ")" << endl; \ } void solve () { map<int , int > mp; int n; cin >> n; for (int i = 0 ; i < n; i++) { int x; cin >> x; for (int j = 2 ; j<=x/j; j++) { while (x % j == 0 ) { mp[j]++; x /= j; } } mp[x]++; } for (auto x : mp) { if (x.first == 1 ) continue ; if (x.second % n != 0 ) { puts ("NO" ); return ; } } puts ("YES" ); }int main () { ios::sync_with_stdio (0 ); cin.tie (0 ); int T; cin >> T; while (T--) solve (); return 0 ; }
CF–记录傻逼瞬间
简单的暴力 maxnum范围开小了 从头WA到尾。。
前缀和 的范围 是远超过1e9的单个数字的范围的。。
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 70 71 72 73 74 75 76 #include <bits/stdc++.h> using namespace std;using ll = long long ;using PII = pair<int , int >;#define pb push_back #define all(x) (x).begin(), (x).end() #define fi first #define se second #define endl '\n' #define debug(x) \ { \ cerr << #x << " = " << x << endl; \ } #define debugfull(x) \ { \ cerr << #x << " = " << x << " (line " << __LINE__ << ")" << endl; \ } const int N = 2e5 ;void solve () { int n; cin >> n; vector<ll> nums (n + 5 ) ; vector<ll> qzh (n + 5 ) ; ll minn = 1e9 + 10 , maxn = -1 ; for (int i = 1 ; i <= n; i++) { cin >> nums[i]; maxn = max (maxn, nums[i]); minn = min (minn, nums[i]); qzh[i] = qzh[i - 1 ] + nums[i]; } ll ret = maxn - minn; if (ret == 0 ) { cout << 0 << endl; return ; } for (int i = 1 ; i < n; i++) { maxn = 0 , minn = 1e18 ; if (n % i != 0 ) continue ; for (int j = i; j <= n; j += i) { maxn = max (maxn, qzh[j] - qzh[j - i]); minn = min (minn, qzh[j] - qzh[j - i]); } ret = max (ret, maxn - minn); } cout << ret << endl; }int main () { ios::sync_with_stdio (0 ); cin.tie (0 ); int T; cin >> T; while (T--) solve (); return 0 ; }
C也是懒得喷。。我艹 vector开在局部 还每次都开2e5赋值0的是什么傻逼 T了一次
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 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 #include <bits/stdc++.h> using namespace std;using ll = long long ;using PII = pair<int , int >;#define pb push_back #define all(x) (x).begin(), (x).end() #define fi first #define se second #define endl '\n' #define debug(x) \ { \ cerr << #x << " = " << x << endl; \ } #define debugfull(x) \ { \ cerr << #x << " = " << x << " (line " << __LINE__ << ")" << endl; \ } const int N = 3e5 ;void solve () { int nums[N] = {0 }; int n; cin >> n; for (int i = 0 ; i < n; i++) { cin >> nums[i]; } ll ret = nums[0 ]; ll l = 0 ; ll sum = 0 ; if (nums[l] > 0 ) { ret = nums[l]; sum = nums[l]; } l++; while (l < n) { if (abs (nums[l] % 2 ) != abs (nums[l - 1 ] % 2 )) { sum += nums[l]; while (sum < 0 && l < n) { l++; sum = nums[l]; ret = max (ret, sum); } ret = max (ret, sum); } else { if (nums[l] > 0 ) { sum = nums[l]; ret = max (sum, ret); } else sum = 0 ; } l++; } cout << ret << endl; }int main () { ios::sync_with_stdio (0 ); cin.tie (0 ); int T; cin >> T; while (T--) solve (); return 0 ; }
emm 感觉这两场状态都很差,题目没看明白 浪费了很多时间。
其实求最大的正方形 不是去整个里面删除 而是在可以删除的线(vBars和hBars)里面找 最长的连续的是多少 画个图 就能看出来 (最后要加一,,也是画图)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution : def maximizeSquareHoleArea (self, n: int , m: int , hBars: List [int ], vBars: List [int ] ) -> int : def f (a ): l = len (a) cnt = 1 ret = 0 for i in range (1 , l): if a[i] == a[i - 1 ] + 1 : cnt += 1 else : ret = max (ret, cnt) cnt = 1 ret = max (ret, cnt) return ret hBars.sort() vBars.sort() x = min (f(hBars), f(vBars)) + 1 return x * x
看清题目!其实就是直接比较两列是否相等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Solution : def areSimilar (self, mat: List [List [int ]], k: int ) -> bool : row = len (mat) col = len (mat[0 ]) if k % col == 0 : return True k %= col now = [[0 ] * col for _ in range (row)] print (mat) for i in range (col): for j in range (row): now[j][i] = mat[j][(i + k) % col] print (now, mat) if now == mat: return True return False
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 class Solution : def lexicographicallySmallestArray (self, nums: List [int ], limit: int ) -> List [int ]: """ 3 1 2 limit = 1 那么1 3 的差大于limit 是不是就不能换了呢? 不是 可以借助2来换 2 1 3 -> 1 2 3 3 5 1 7 limit = 2 可以换到1 3 5 7 这说明limit限制内的所有数 都可以被换成从小到大的数 这被称为一个连通块(类似图论的概念) 再看 2 4 22 20 3 21 1 这组数有两个连通块 1 2 3 4 可以按顺序 20 21 22 可以按顺序 但是 他们只能在各自的块内交换 即 1 2 20 21 3 22 4 用 排序+分组循环 """ n = len (nums) a = sorted (zip (nums, range (n))) i = 0 ans = [0 ] * n while i < n: st = i i += 1 while i < n and a[i][0 ] <= a[i - 1 ][0 ] + limit: i += 1 sub = a[st:i] sub_idx = sorted (i for _, i in sub) for j, (x, _) in zip (sub_idx, sub): ans[j] = x return ans