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;
}
posted @ 2025-02-09 19:25  Ke_scholar  阅读(14)  评论(0)    收藏  举报