Practice.
A. Working Week
题意
给定 \(n\) 个格子,规定第 \(1\) 个格子不能标记,第 \(n\) 个格子一定被标记。按照要求标记三个点后,格子被划分成三段,记长度为 \(l_1, l_2, l_3\)。
输出 \(\min(|l_1 - l_2|, |l_2 - l_3|, |l_3 - l_1|)\) 的最大值。
思路
显然,我们可以在第二个点做上标记,这样就可以让差值尽可能大。
那么,我们来考虑剩下那个点。因为对称性,我们不妨令 \(l_2 \leq l_3\)。
很明显,\(\min(|l_1 - l_2|, |l_2 - l_3|, |l_3 - l_1|) = \min(l_2 - 1, n - 4 - 2l_2)\)
如果前者更小,那就需要满足 \(l_2 \leq \frac{n}{3} - 1\),那么 \(l_2 - 1\) 的最大值就是 \(\frac{n}{3} - 2\)。
如果后者更小,那就需要满足 \(l_2 \geq \frac{n}{3} - 1\),那么 \(n - 4 - 2l_2\) 的最大值就是 \(n - 4 - 2(\frac{n}{3} - 1) = \frac{n}{3} - 2\)。
所以,答案就是 \(\frac{n}{3} - 2\)。
时间复杂度:\(O(1)\)
对应AC代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve(){
int n;
cin >> n;
cout << n / 3 - 2 << '\n';
}
signed main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while(t --) solve();
}
其实也可以猜出来(x
B. Tea with Tangerines
题意
给定长度为 \(n\) 的序列 \(a\),其中 \(a_i\) 可切割为任意段。在切割结束后,需要满足任意两段中 较小的那段的 两倍 严格小于 较长那段。输出需要切割的最小次数。
思路
首先,我们先设最小那段为 \(x\),在按照同一长度 \(2x-1\) 切割后,我们有可能会多出一小段长度小于 \(x\) 的,但我们显然可以各取前面长为 \(2x - 1\) 的那几段的一部分来填补,而且一定不会让前面的那几段减到比 \(x\) 小。
那么,答案就是 \(\displaystyle{\sum_{i=1}^{n}\left\lceil\frac{a_i}{2 \cdot x - 1}\right\rceil}\)
显然,我们希望尽可能减少切割次数,也就是说至少有一段是不用切的。
那么,升序排序 \(a\) 后,\(\displaystyle{\sum_{i=1}^{n}\left\lceil\frac{a_i}{2 \cdot a_1 - 1}\right\rceil}\) 就是答案。
时间复杂度:\(O(n)\)
对应AC代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve(){
int n;
cin >> n;
int ans = 0, a0;
cin >> a0;
for(int i=1;i<n;i++){
int cur;
cin >> cur;
ans += (cur - 1) / (2 * a0 - 1);
}
cout << ans << '\n';
}
signed main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while(t --) solve();
}
有点抽象
C. Phase Shift
题意
给定一个由大写字母组成的字符串,构造一个字符串映射,满足映射对应的有向图为一个包含 \(A - Z\) 内所有字母的单环。
输出映射后字典序最小的结果。
思路
我们可以暴力枚举每一位,对于该位,如果我们并没有创建映射,我们就暴力按字母表顺序枚举所有字母,找出第一个没有被创建且和原字母不一样的字母并创建映射;如果创建了映射,我们直接使用该映射即可。
时间复杂度:\(O(nm)\)
对应AC代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int, int>
#define fs first
#define sc second
const int N = 2e5 + 10, inf = 0x3f3f3f3f3f3f3f3f, mod = 1e9 + 7;
void init(){}
void solve() {
int n;
string t;
cin >> n >> t;
vector<int> e(26, -1), re(26, -1);
for(int i=0;i<n;i++){
int cur = t[i] - 'a';
if(e[cur] == -1) {
for (int j = 0; j < 26; j++) {
if (re[j] == -1) {
int last = j, cnt = 0;
while (e[last] != -1) last = e[last], cnt++;
if (last != cur || cnt == 25) {
e[cur] = j, re[j] = cur;
break;
}
}
}
}
t[i] = (char) (e[cur] + 'a');
}
cout << t << '\n';
}
signed main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
init();
int t = 1;
cin >> t;
while(t --) solve();
}
就很暴力(x
D. Meta-set
题意
给定 \(n\) 个长度为 \(m\) 的序列,序列元素由 \(0, 1, 2\) 构成。
若一个 由 \(3\) 个不同序列 组成的三元组 满足 对于 所有序列的 第 \(i\) 个元素组成的 新序列 均为相等的值或为 \(012\) 的排列,那么这个三元组是好的。
输出序列的所有五元组中 有至少两个好三元组 的个数。
思路
(题意还是介绍得有点绕,可以去看原题的样例)
首先,数据量并不大,\(O(n ^ 2)\) 的复杂度是完全可以接受的,那么我们不妨去枚举所有的三元组中的其中两个序列,然后我们就可以按照题意构造出第三个序列,我们直接记录构造出的这个序列可以对应多少个 "两个序列"。
记录完后,我们直接枚举所有序列,对于对应的个数 \(cnt\),我们就可以得到 \(C^2_{cnt}\) 个满足条件的五元组。
时间复杂度:\(O(n^2 \log n)\)
对应AC代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int, int>
#define fs first
#define sc second
const int N = 2e5 + 10, inf = 0x3f3f3f3f3f3f3f3f, mod = 1e9 + 7;
void init(){}
void solve() {
int n, k;
cin >> n >> k;
vector<vector<int>> a(n, vector<int>(k));
for(int i=0;i<n;i++)
for(int j=0;j<k;j++)
cin >> a[i][j];
map<vector<int>, int> cnt;
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++){
vector<int> need(k);
for(int t=0;t<k;t++){
need[t] = a[i][t] == a[j][t] ? a[i][t] : 3 - a[i][t] - a[j][t];
}
cnt[need] ++;
}
int ans = 0;
for(int i=0;i<n;i++){
if(cnt[a[i]] >= 2) ans += cnt[a[i]] * (cnt[a[i]] - 1) / 2;
}
cout << ans << '\n';
}
signed main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
init();
int t = 1;
//cin >> t;
while(t --) solve();
}
有点像状压