回头看,轻舟已过万重山.|

Ke_scholar

园龄:2年1个月粉丝:30关注:10

2025-02-09 19:25阅读: 6评论: 0推荐: 0

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=i}^r a_i \oplus b_j \]

\[= \sum_{i=l}^r \sum_{j=i}^n a_i \oplus b_j - \sum_{i=l}^r \sum_{j=r+1}^n 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 中国大陆许可协议进行许可。

posted @   Ke_scholar  阅读(6)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起