2025牛客寒假算法基础集训营6

2025牛客寒假算法基础集训营6

A-复制鸡_2025牛客寒假算法基础集训营6 (nowcoder.com)

思路

将连续的元素看成一个即可。

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

void solve() {

	int n;
	cin >> n;

	vector<int> a;
	for (int i = 1; i <= n; i ++) {
		int x;
		cin >> x;
		if (a.empty() || x != a.back()) {
			a.emplace_back(x);
		}
	}

	cout << a.size() << "\n";

}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int t;
	cin >> t;
	while (t--) {
		solve();
	}

	return 0;
}

B-好伙计猜拳_2025牛客寒假算法基础集训营6 (nowcoder.com)

思路

题目要求通过删除或交换记录使得比赛序列合法且代价最小。采用动态规划,设 \(\text{dp}[i][0/1/2]\) 表示处理到第 \(i\) 条记录时的三种状态:

  • \(0\):保留当前记录不交换,且满足 \(a_i \geq a_j\)
  • \(1\):删除当前记录;
  • \(2\):交换当前记录的两人得分,且满足交换后 \(b_i \geq a_j\)

初始化 \(\text{dp}[0][0] = 0\)\(\text{dp}[0][1] = c_1\)\(\text{dp}[0][2] = c_2\)。对于每条记录 \(i\),遍历前面所有可能的 \(j\),转移方程为:

\[\text{dp}[i][0] = \min \begin{cases} c_1 \cdot i, \\ \text{dp}[j][0] + c_1 \cdot (i - 1 - j) \quad \text{if} \quad a_i \geq a_j \land b_i \geq b_j, \\ \text{dp}[j][2] + c_1 \cdot (i - 1 - j) \quad \text{if} \quad a_i \geq b_j \land b_i \geq a_j. \end{cases} \]

\[\text{dp}[i][1] = \min \begin{cases} c_1 \cdot (i + 1), \\ \min(\text{dp}[j][0], \text{dp}[j][1], \text{dp}[j][2]) + c_1 \cdot (i - j). \end{cases} \]

\[\text{dp}[i][2] = \min \begin{cases} c_1 \cdot i + c_2, \\ \text{dp}[j][0] + c_1 \cdot (i - 1 - j) + c_2 \quad \text{if} \quad b_i \geq a_j \land a_i \geq b_j, \\ \text{dp}[j][2] + c_1 \cdot (i - 1 - j) + c_2 \quad \text{if} \quad b_i \geq b_j \land a_i \geq a_j. \end{cases} \]

最终答案为 \(\min(\text{dp}[n-1][0], \text{dp}[n-1][1], \text{dp}[n-1][2])\),时间复杂度 \(O(n^2)\)

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

void solve() {

	int n;
	i64 c[3] {};
	cin >> n >> c[1] >> c[2];

	vector<array<int, 2>> a(n);
	for (auto &[x, y] : a) {
		cin >> x >> y;
	}

	constexpr i64 inf = 1E16;
	vector dp(n, array<i64, 3> {inf, inf, inf});
	dp[0][0] = 0, dp[0][1] = c[1], dp[0][2] = c[2];
	for (int i = 1; i < n; i ++) {
		dp[i][0] = c[1] * i;
		for (int j = 0; j < i; j ++) {
			if (a[i][0] >= a[j][0] && a[i][1] >= a[j][1]) {
				dp[i][0] = min(dp[i][0], dp[j][0] + c[1] * (i - 1 - j));
			}
			if (a[i][0] >= a[j][1] && a[i][1] >= a[j][0]) {
				dp[i][0] = min(dp[i][0], dp[j][2] + c[1] * (i - 1 - j));
			}
		}
		dp[i][1] = c[1] * (i + 1);
		for (int j = 0; j < i; j ++) {
			dp[i][1] = min(dp[i][1], min({dp[j][0], dp[j][1], dp[j][2]}) + c[1] * (i - j));
		}
		dp[i][2] = c[1] * i + c[2];
		for (int j = 0; j < i; j ++) {
			if (a[i][1] >= a[j][0] && a[i][0] >= a[j][1]) {
				dp[i][2] = min(dp[i][2], dp[j][0] + c[1] * (i - 1 - j) + c[2]);
			}
			if (a[i][1] >= a[j][1] && a[i][0] >= a[j][0]) {
				dp[i][2] = min(dp[i][2], dp[j][2] + c[1] * (i - 1 - j) + c[2]);
			}
		}

	}

	cout << min({dp[n - 1][0], dp[n - 1][1], dp[n - 1][2]}) << "\n";

}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int t;
	cin >> t;
	while (t--) {
		solve();
	}

	return 0;
}

C-数列之和_2025牛客寒假算法基础集训营6 (nowcoder.com)

思路

打表,在OEIS上找到的规律。

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

void solve() {

    i64 k;
    cin >> k;
    
    auto lg2 = [](i64 x)->i64{
        return __lg(x)/__lg(2);
    };
    
    cout << 2 * (k + lg2(k + lg2(k))) << "\n";

}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int t;
    cin >> t;
    while (t--) {
        solve();
    }

    return 0;
}

F-薪得体会_2025牛客寒假算法基础集训营6 (nowcoder.com)

思路

题目要求通过调整面试顺序,使得小鸡能获得的最高年薪最大化。解法核心如下:

首先将所有公司按 \(a_i\) 升序排序。设 \(\text{dp}[i]\) 表示前 \(i\) 家公司中小鸡能获得的最高年薪。对于第 \(i\) 家公司,若前 \(i-1\) 家公司中已有年薪大于等于 \(a_i\) 的 offer,则当前 offer 可提升为 \(a_i + b_i\)。转移方程为:

\[\text{dp}[i] = \max \begin{cases} \text{dp}[i-1], \\ a_i, \\ a_i + b_i \quad \text{if} \quad \text{dp}[i-1] \geq a_i. \end{cases} \]

最终答案为 \(\text{dp}[n]\),时间复杂度为 \(O(n \log n)\)

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

void solve() {

	int n;
	cin >> n;

	vector<pair<int, int>> p(n);
	for (auto &[a, b] : p) {
		cin >> a >> b;
	}

	ranges::sort(p);

	vector<int> dp(n);
	for (int i = 0; i < n; i += 1) {
		if (i) {
			dp[i] = max(dp[i - 1], p[i - 1].first + p[i - 1].second);
		}
		dp[i] = max(dp[i], p[i].first);
		if (i and dp[i - 1] >= p[i].first) {
			dp[i] = max(dp[i], p[i].first + p[i].second);
		}
	}

	cout << dp[n - 1] << "\n";

}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int t;
	cin >> t;
	while (t--) {
		solve();
	}

	return 0;
}

H-小鸡的排列构造_2025牛客寒假算法基础集训营6 (nowcoder.com)

思路

若区间长度奇偶性为偶数(即 \(r_i - l_i\) 为奇数),则输出倒序排列 \([n, n-1, \ldots, 1]\)。此时任意子区间排序后,原中间位置的元素必改变,满足条件。

若区间长度奇偶性为奇数(即 \(r_i - l_i\) 为偶数),构造分块排列,形如 \([n-1, n, n-3, n-2, \ldots, 1, 2]\)。此时每个子区间排序后,原位置 \(c_i\) 的元素必不处于排序后的原位。

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

void solve() {

	int n, m;
	cin >> n >> m;

	vector<int> l(m), r(m), c(m);
	for (int i = 0; i < m; i += 1) {
		cin >> l[i] >> r[i] >> c[i];
	}

	if ((r[0] - l[0]) % 2) {
		for (int i = n; i >= 1; i -= 1){
			cout << i << " ";
		}
	} else {
		for (int i = 1; i <= n; i += 2) {
			if (i < n) {
				cout << n - i << " " << n - i + 1 << " ";
			} else {
				cout << "1 ";
			}
		}
	}
	cout << "\n";

}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int t;
	cin >> t;
	while (t--) {
		solve();
	}

	return 0;
}

I-小鸡的排列构造的checker_2025牛客寒假算法基础集训营6 (nowcoder.com)

思路

转化为求区间内小于 \(x\) 的个数有多少个即可。

利用树状数组维护前缀和,统计每个位置 \(i\) 之前小于等于 \(p[c_i]\) 的元素个数。对于每个询问 \([l_i, r_i, c_i]\),通过差分计算排序后 \(c_i\) 的位置:首先记录 \([1, l_i-1]\) 中小于等于 \(p[c_i]\) 的元素个数 \(A\),再记录 \([1, r_i]\) 中小于等于 \(p[c_i]\) 的元素个数 \(B\),则排序后 \(c_i\) 的位置为 \(l_i - 1 + (B - A)\)

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

template<typename T>
struct BIT {
	int n;
	vector<T> w;

	BIT() {}
	BIT(int n) {
		this->n = n;
		w.resize(n + 1);
	}
	void update(int x, T k) {
		for (; x <= n; x += x & -x) {
			w[x] += k;
		}
	}
	T ask(int x) {
		T ans = 0;
		for (; x; x -= x & -x) {
			ans += w[x];
		}
		return ans;
	}
};

void solve() {

	int n, m;
	cin >> n >> m;

	vector<int> p(n + 1);
	for (int i = 1; i <= n; i ++) {
		cin >> p[i];
	}

	vector<int> ans(m + 1);
	vector g(n + 1, vector<array<int, 3>>());
	for (int i = 1; i <= m; i ++) {
		int l, r, c;
		cin >> l >> r >> c;
		g[l - 1].push_back({ -1, p[c], i});
		g[r].push_back({1, p[c], i});
		ans[i] += l - 1;
	}

	BIT<int> bit(n + 1);
	for (int i = 1; i <= n; i ++) {
		bit.update(p[i], 1);
		for (auto &[k, x, id] : g[i]) {
			ans[id] += k * bit.ask(x);
		}
	}

	for (int i = 1; i <= m; i ++) {
		cout << ans[i] << "\n";
	}

}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int t;
	cin >> t;
	while (t--) {
		solve();
	}

	return 0;
}

J-铁刀磨成针_2025牛客寒假算法基础集训营6 (nowcoder.com)

思路

设选择 \(k\) 次磨刀(\(0 \leq k \leq \min(y, n)\)),每次磨刀后攻击,攻击力依次为 \(x+1, x+2, \ldots, x+k\),总伤害为等差数列和 \(\frac{k(2x +k +1)}{2}\)。剩余 \(n -k\) 回合攻击次数为 \(m = \min(n -k, x +k)\),伤害为 \(\frac{m(2(x +k) -m +1)}{2}\)。遍历所有 \(k\),取总伤害的最大值即可。时间复杂度为 \(O(\min(y, n))\)

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

void solve() {

	i64 n, x, y;
	cin >> n >> x >> y;

	i64 ans = 0;

	i64 m = min(y, n);
	for (int i = 0; i <= m; i ++) {
		i64 res = 0;
		res += (x + 1) * min(y, n);
		if (y < n) {
			res += x * (x + 1) / 2;
			i64 d = min(n - y, x);
			res -= (x - d) * (x - d + 1) / 2;
		}
		n--;
		y--, x++;
		ans = max(res, ans);;
	}

	cout << ans << "\n";

}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int t;
	cin >> t;
	while (t--) {
		solve();
	}

	return 0;
}

K-鸡翻题_2025牛客寒假算法基础集训营6 (nowcoder.com)

思路

由于书的页码是连续的,且翻页操作会改变当前页码,我们需要分析页码的奇偶性。设当前页码为 \(x\)\(x+1\),翻页后的页码为 \(a\)\(a+1\),则 \(a + (a+1) = y\),即 \(2a + 1 = y\)。因此,\(y\) 必须为奇数,且满足 \(a = \frac{y-1}{2}\)。此外,翻页后的页码 \(a\) 必须与当前页码 \(x\) 的奇偶性相同,即 \(\frac{y-1}{2} \equiv x \pmod{2}\)

综上,若 \(y\) 为偶数\((0\text{除外})\),或 \(\frac{y-1}{2}\) 的奇偶性与 \(x\) 不同,则输出“NO”;否则输出“YES”。

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

void solve() {

	int x, y;
	cin >> x >> y;

	if ((y % 2 == 0 || ((y - 1) / 2) % 2 != x % 2) && y) {
		cout << "NO\n";
	} else {
		cout << "YES\n";
	}

}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int t;
	cin >> t;
	while (t--) {
		solve();
	}

	return 0;
}

L-变鸡器_2025牛客寒假算法基础集训营6 (nowcoder.com)

思路

先判断能否匹配字符串,然后再判断其余多出来的字符的最大个数有没有超过一半,如果超过了,则说明最后一定会有相同字符留下,而题目要求的是不同字符,所以不可行。

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

void solve() {

	int n;
	cin >> n;

	string s;
	cin >> s;

	string t = "CHICKEN";
	int idx = 0;

	vector<int> cnt(26);
	for (auto c : s) {
		if (idx < t.size() && c == t[idx]) {
			idx ++;
		} else {
			cnt[c - 'A']++;
		}
	}

	if (idx == 7) {
		int Max = *max_element(cnt.begin(), cnt.end());
		if ((n - 7) % 2 == 0 && Max <= (n - 7) / 2) {
			cout << "YES\n";
			return;
		}
	}

	cout << "NO\n";

}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int t;
	cin >> t;
	while (t--) {
		solve();
	}

	return 0;
}
posted @ 2025-02-16 20:47  Ke_scholar  阅读(51)  评论(0)    收藏  举报