2025牛客寒假算法基础集训营4
2025牛客寒假算法基础集训营4
Tokitsukaze and Balance String (easy)
思路
暴力枚举即可,复杂度 \(\mathcal{O}(2^nn^2)\)。
代码
#include <bits/stdc++.h> using namespace std; using i64 = long long; //------取模机------// using Z = MInt<MOD[1]>; //------取模机------// void solve() { int n; cin >> n; string s; cin >> s; int p = 0; for (int i = 0; i < n; i ++) { p += s[i] == '?'; } Z ans = 0; string t = s; for (int i = 0; i < (1 << p); i ++) { int idx = 0; for (int j = 0; j < n; j ++) { if (s[j] != '?') { t[j] = s[j]; } else { t[j] = ((i >> idx) & 1) + '0'; idx += 1; } } int v = 0; for (int j = 0; j < n; j ++) { t[j] = t[j] == '1' ? '0' : '1'; int ol = 0, lo = 0; for (int k = 0; k < n - 1; k ++) { if (t[k] == '0' && t[k + 1] == '1') { ol ++; } if (t[k] == '1' && t[k + 1] == '0') { lo ++; } } t[j] = t[j] == '1' ? '0' : '1'; if (ol == lo) { v ++; } } ans += v; } cout << ans << "\n"; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { solve(); } return 0; }
Tokitsukaze and Balance String (hard)
思路
找规律可以发现,影响平衡的时候当且仅当首尾字符不同,所以,根据首尾的字符组合,看能组合出多少种不同情况,当首尾相同时,则一定存在平衡,所以方案数为 \((C_1\times2+C_0\times(n-2))\times2^{cnt}(cnt\) 为\(\sum\limits_{i=2}^{n-1}[s_i='?'])\)。
代码
#include <bits/stdc++.h> using namespace std; using i64 = long long; //------取模机------// using Z = MInt<MOD[1]>; //------取模机------// void solve() { int n; cin >> n; string s; cin >> s; if (n == 1) { cout << (s == "?" ? 2 : 1) << "\n"; return ; } vector<int> A, B; if (s[0] == '?') { A = {0, 1}; } else { A = {s[0] - '0'}; } if (s.back() == '?') { B = {0, 1}; } else { B = {s.back() - '0'}; } int cnt[2] {}; for (auto x : A) { for (auto y : B) { cnt[x ^ y] ++; } } Z p = 1; for (int i = 1; i < n - 1; i ++) { if (s[i] == '?') { p *= 2; } } Z ans = (cnt[1] * 2 + cnt[0] * (n - 2)) * p; cout << ans << "\n"; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { solve(); } return 0; }
Tokitsukaze and Concatenate Palindrome
思路
优先用长的去补足短的,计算补足短的需要多少字符,然后看长字符串里奇数字符的个数能否补足,能补足的话那么多余的奇数字符还需要拿一半出来补足另一半。
代码
#include <bits/stdc++.h> using namespace std; using i64 = long long; void solve() { int n, m; cin >> n >> m; string a, b; cin >> a >> b; if (n < m) { swap(n, m); swap(a, b); } vector<int>cnt1(26), cnt2(26); for (auto c : a) { cnt1[c - 'a'] ++; } for (auto c : b) { cnt2[c - 'a']++; } int ans = 0; for (int i = 0; i < 26; i ++) { if (cnt1[i] < cnt2[i]) { ans += cnt2[i] - cnt1[i]; cnt1[i] = 0; } else { cnt1[i] -= cnt2[i]; } } n -= m; int t = 0; for (int i = 0; i < 26; i ++) { t += cnt1[i] % 2; } if (t >= ans) { t -= ans; cout << ans + t / 2 << "\n"; } else { cout << ans << "\n"; } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { solve(); } return 0; }
Tokitsukaze and Dragon's Breath
思路
每个“龙之吐息”的攻击范围由其所在的主对角线(\(i - j\) 为常数)和副对角线(\(i + j\) 为常数)共同确定。总击败数为这两条对角线覆盖的所有格子的怪物数之和,但攻击点 \((i,j)\) 会被重复计算一次,需减去其自身值。预处理所有主副对角线的总和,遍历每个格子 \((i,j)\),计算 \(sum(i-j) + sum(i+j) - a_{i,j}\) 的最大值即为答案。
代码
#include <bits/stdc++.h> using namespace std; using i64 = long long; void solve() { int n, m; cin >> n >> m; vector a(n, vector<int>(m)); map<int, i64> mp1, mp2; for (int i = 0; i < n; i ++) { for (int j = 0; j < m; j ++) { cin >> a[i][j]; mp1[i - j] += a[i][j]; mp2[i + j] += a[i][j]; } } i64 ans = 0; for (int i = 0; i < n; i ++) { for (int j = 0; j < m; j ++) { ans = max(ans, mp1[i - j] + mp2[i + j] - a[i][j]); } } cout << ans << "\n"; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { solve(); } return 0; }
Tokitsukaze and Pajama Party
思路
用前缀和记录u
的个数,每遇到一次uwawauwa
,则累加一次 \(pre_{i-2}\) 即可。
代码
#include <bits/stdc++.h> using namespace std; using i64 = long long; void solve() { int n; cin >> n; string s; cin >> s; s = " " + s; i64 ans = 0; vector<int> pre(n + 1); for (int i = 1; i <= n; i ++) { pre[i] = pre[i - 1] + (s[i] == 'u'); if (s.substr(i, 8) == "uwawauwa") { ans += pre[i - 2]; } } cout << ans << "\n"; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { solve(); } return 0; }
Tokitsukaze and Shawarma
思路
代码
#include <bits/stdc++.h> using namespace std; using i64 = long long; void solve() { int x, y, z, a, b, c; cin >> x >> y >> z >> a >> b >> c; cout << max({x * a, y * b, z * c}) << "\n"; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { solve(); } return 0; }
Tokitsukaze and XOR-Triangle
思路
来自出题人题解。
如果求的是 \(\sum_{i=1}^r \sum_{j=1}^r a_i \oplus b_j\),那就是个大家都会的经典原题。但现在求的是 \(\sum_{i=1}^r \sum_{j=i}^r a_i \oplus b_j\)。
直接做不好做,考虑把它拆解一下。
先看后一半 \(\sum_{i=l}^r \sum_{j=r+1}^n a_i \oplus b_j\),这两个区间没有相交,所以可以转化成类似 \(\sum_{i=1}^r \sum_{j=i}^r a_i \oplus b_j\) 的求法。即拆位后统计 \(a_l, a_{l+1}, \ldots, a_r\) 中这一位上有多少个 0 和 1;再统计 \(b_{r+1}, b_{r+2}, \ldots, b_n\) 中这一位上有多少个 \(0\) 和 \(1\),然后乘一乘。
再看前一半 \(\sum_{i=l}^r \sum_{j=i}^n a_i \oplus b_j\)。这一部分可以预处理出对于每个 \(i\),\(f_i = \sum_{j=i}^n a_i \oplus b_j\)。然后记 \(g_i = \sum_{j=1}^i f_j\),那么 \(\sum_{i=l}^r \sum_{j=i}^n a_i \oplus b_j = g_r - g_{l-1}\)。
然后就做完了。时间复杂度 \(O(n \log V)\),\(V\) 是值域 \(10^9\)。
代码
#include <bits/stdc++.h> using namespace std; using i64 = long long; //------取模机------// using i64 = long long; template<class T> constexpr T power(T a, i64 b) { T res {1}; for (; b; b /= 2, a *= a) { if (b % 2) { res *= a; } } return res; } // 快速幂 constexpr i64 mul(i64 a, i64 b, i64 p) { i64 res = a * b - i64(1.L * a * b / p) * p; res %= p; if (res < 0) { res += p; } return res; } // 取模乘 template<i64 P> struct MInt { i64 x; constexpr MInt() : x {0} {} constexpr MInt(i64 x) : x {norm(x % getMod())} {} static i64 Mod; constexpr static i64 getMod() { if (P > 0) { return P; } else { return Mod; } } constexpr static void setMod(i64 Mod_) { Mod = Mod_; }//只有P<=0, setMod才生效 constexpr i64 norm(i64 x) const { if (x < 0) { x += getMod(); } if (x >= getMod()) { x -= getMod(); } return x; } constexpr i64 val() const { return x; } constexpr MInt operator-() const { MInt res; res.x = norm(getMod() - x); return res; } constexpr MInt inv() const { return power(*this, getMod() - 2); } constexpr MInt &operator*=(MInt rhs) & { if (getMod() < (1ULL << 30)) { x = x * rhs.x % int(getMod()); } else { x = mul(x, rhs.x, getMod()); } return *this; } constexpr MInt &operator+=(MInt rhs) & { x = norm(x + rhs.x); return *this; } constexpr MInt &operator-=(MInt rhs) & { x = norm(x - rhs.x); return *this; } constexpr MInt &operator/=(MInt rhs) & { return *this *= rhs.inv(); } friend constexpr MInt operator*(MInt lhs, MInt rhs) { MInt res = lhs; res *= rhs; return res; } friend constexpr MInt operator+(MInt lhs, MInt rhs) { MInt res = lhs; res += rhs; return res; } friend constexpr MInt operator-(MInt lhs, MInt rhs) { MInt res = lhs; res -= rhs; return res; } friend constexpr MInt operator/(MInt lhs, MInt rhs) { MInt res = lhs; res /= rhs; return res; } friend constexpr std::istream &operator>>(std::istream &is, MInt &a) { i64 v; is >> v; a = MInt(v); return is; } friend constexpr std::ostream &operator<<(std::ostream &os, const MInt &a) { return os << a.val(); } friend constexpr bool operator==(MInt lhs, MInt rhs) { return lhs.val() == rhs.val(); } friend constexpr bool operator!=(MInt lhs, MInt rhs) { return lhs.val() != rhs.val(); } friend constexpr bool operator<(MInt lhs, MInt rhs) { return lhs.val() < rhs.val(); } }; constexpr int MOD[] = {998244353, 1000000007}; using Z = MInt<MOD[1]>; //------取模机------// void solve() { int n, q; cin >> n >> q; vector<int> a(n + 1), b(n + 1); vector cnta(n + 1, vector<int>(34)); vector cntb(n + 1, vector<int>(34)); for (int i = 1; i <= n; i ++) { cin >> a[i]; int x = a[i]; cnta[i] = cnta[i - 1]; for (int j = 30; j >= 0; j --) { if ((x >> j) & 1) { cnta[i][j] ++; } } } for (int i = 1; i <= n; i ++) { cin >> b[i]; int x = b[i]; cntb[i] = cntb[i - 1]; for (int j = 30; j >= 0; j --) { if ((x >> j) & 1) { cntb[i][j] ++; } } } vector<Z> suf(n + 1); for (int i = n; i > 0; i --) { for (int j = 30; j >= 0; j --) { Z a1 = ((a[i] >> j) & 1), a0 = 1 - a1; Z b1 = cntb[n][j] - cntb[i - 1][j], b0 = (n - i + 1) - b1; suf[i] += (a1 * b0 + b1 * a0) * (1 << j); } } vector<Z> pre(n + 1); for (int i = 1; i <= n; i ++) { pre[i] += pre[i - 1] + suf[i]; } while (q--) { int l, r; cin >> l >> r; Z ans = 0; for (int i = 30; i >= 0; i --) { Z a1 = cnta[r][i] - cnta[l - 1][i], a0 = r - l + 1 - a1; Z b1 = cntb[n][i] - cntb[r][i], b0 = n - r - b1; ans += (a1 * b0 + b1 * a0) * (1 << i); } Z res = 0; for (int i = l; i <= r; i ++) { for (int j = i; j <= r; j ++) { res += a[i] ^ b[j]; } } ans = pre[r] - pre[l - 1] - ans; cout << ans << "\n"; } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { solve(); } return 0; }
本文作者:Ke_scholar
本文链接:https://www.cnblogs.com/Kescholar/p/18706522
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步