VP Educational Codeforces Round 60 (Rated for Div. 2)
A. Best Subsegment
题意:找出最长的平均值最大的子区间。
显然平均值最大的子区间的所有元素都数组最大值。因为一旦有一个数不是最大值,那么平均数显然小于最大值,而单个最大值的平均数就是最大值,可以发现最大值就是最大平均数的值。
那么找最长的连续最大值就行。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
int max = *std::max_element(a.begin(), a.end());
int ans = 0;
for (int i = 0; i < n; ++ i) {
if (a[i] == max) {
int j = i;
while (j < n && a[i] == a[j]) {
++ j;
}
ans = std::max(ans, j - i);
i = j - 1;
}
}
std::cout << ans << "\n";
}
B. Emotes
题意:\(n\)个数,操作\(m\)次,每次选一个数得到它的值,每个数不能连续选超过\(k\)次。求最大价值。
我们只会操作最大值和次大值(次大值可能等于最大值)。那么每次操作\(k\)次最大值,然后操作一次次大值,如此循环直到操作完\(m\)次。
点击查看代码
void solve() {
i64 n, m, k;
std::cin >> n >> m >> k;
std::vector<i64> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
std::ranges::sort(a, std::greater<i64>());
i64 t = m / (k + 1);
i64 ans = t * (a[0] * k + a[1]) + (m - t * (k + 1)) * a[0];
std::cout << ans << "\n";
}
C. Magic Ship
题意:从\((x1, y1)\)走到\((x2, y2)\),给你一个循环序列,每个位置代表一个移动的方向,每次移动必须按照序列给定的方向移动一格,然后每次你要再选择一个方向移动一格。求走到\((x2, y2)\)的最小时间。
如果在时间\(t\),我们可以用前缀和计算移动序列对坐标的贡献,然后可以得到通过这个序列\(x\)和\(y\)分别移动到了哪里,我们还有剩下\(t\)次自己选择的移动,那么\(t\)需要大于等于\(|x - x1| + |y - y2|\)。如果剩余步数是偶数,我们可以反复选两个相反的方向抵消,如果是奇数,无法到达。貌似无法做了,但还是有二分性的,如果\(t \geq |x - x1| + |y - y2|\)我们就认为它可以,那么因为\(t - |x - x1| + |y - y2|\)最小是\(0\),所有当这个差值为奇数的时候我们也认为它可以,任何缩小右边界,这样最终答案的这个差值一定是偶数。
点击查看代码
void solve() {
i64 x1, y1, x2, y2;
std::cin >> x1 >> y1 >> x2 >> y2;
int n;
std::cin >> n;
std::string s;
std::cin >> s;
std::vector<i64> prex(n + 1), prey(n + 1);
for (int i = 0; i < n; ++ i) {
prex[i + 1] = prex[i];
prey[i + 1] = prey[i];
if (s[i] == 'U') {
prey[i + 1] += 1;
} else if (s[i] == 'D') {
prey[i + 1] -= 1;
} else if (s[i] == 'L') {
prex[i + 1] -= 1;
} else {
prex[i + 1] += 1;
}
}
auto check = [&](i64 d) -> i64 {
i64 t = d / n;
i64 x = x1 + prex[n] * t, y = y1 + prey[n] * t;
x += prex[d % n], y += prey[d % n];
return std::abs(x - x2) + std::abs(y - y2);
};
i64 l = 1, r = 1e16;
while (l < r) {
i64 mid = l + r >> 1ll;
if (check(mid) <= mid) {
r = mid;
} else {
l = mid + 1;
}
}
if (check(l) > l) {
std::cout << -1 << "\n";
} else {
std::cout << l << "\n";
}
}
D. Magic Gems
题意:用价值为\(1\)和价值为\(m\)的物品填充\(n\)的空间,问有多少种填法。
根据经验,求方案数的题目要么是\(dp\)要么是组合数学,而这个题\(n\)的范围对于组合数学来说也太大了,有溢出风险,而且也无法做。那么考虑\(dp\)。
记\(f[i]\)为\(i\)的空间的方案数,那么如果\(i < m, f[i] = 1\),否则\(f[i] = f[i - 1] + f[i - m]\)。但这个复杂度是\(O(n)\),也无法接受。
发现\(n\)很大,\(m\)很小。我们联想到矩阵快速幂。然后尝试构造矩阵,发现\([f_{i-1}, f_{i-2}, ... , f_{i-m}]\)如果要推出\([f_i, f_{i-1}, ... , f_{i-m+1}]\)。可以得到以下矩阵:
也就是\(mat[0][0] = mat[m - 1][0] = mat[i][i + 1] = 1\)。
点击查看代码
const int mod = 1000000007, N = 110;
using Mat = std::array<std::array<int, N>, N>;
struct Matrix {
Mat mat;
Matrix() {
init();
}
void init() {
for (int i = 0; i < N; ++ i) {
for (int j = 0; j < N; ++ j) {
mat[i][j] = 0;
}
}
}
void one() {
init();
for (int i = 0; i < N; ++ i) {
mat[i][i] = 1;
}
}
};
Matrix operator * (const Matrix & a, const Matrix & b) {
Matrix res;
for (int k = 0; k < N; ++ k) {
for (int i = 0; i < N; ++ i) {
for (int j = 0; j < N; ++ j) {
res.mat[i][j] = (res.mat[i][j] + (i64)a.mat[i][k] * b.mat[k][j] % mod) % mod;
}
}
}
return res;
}
Matrix power(Matrix a, i64 b) {
Matrix res;
res.one();
for (; b ; b >>= 1, a = a * a) {
if (b & 1) {
res = res * a;
}
}
return res;
}
void solve() {
i64 n, m;
std::cin >> n >> m;
Matrix a;
for (int i = 0; i < m; ++ i) {
a.mat[i][i + 1] = 1;
}
a.mat[0][0] = a.mat[m - 1][0] = 1;
auto ans = power(a, n);
std::cout << ans.mat[0][0] << "\n";
}
E. Decypher the String
题意:交互题。有一个字符串和一个操作序列,我们不知道这个字符串和操作序列。每次操作是交换字符串两个位置的字符。选择给你操作完后的字符串,你可以询问三次,每次给出一个长度为\(n\)的字符串,会返回一个这个字符串经过操作序列所有操作后的字符串。求原字符串。
如果是一个排列,显然我们可以直接给出\(1, 2, .. , n - 1, n\),根据返回的数组就可以直到每个位置最终被交换到了哪个位置。
但这个题目字符集只有\(26\),无法构造一个长度为\(n\)的排列。不过我们可以继续询问\(26个a, 26个b, ... ,26个z\),以及\(26\times26个a, 26\times26个b, ... ,26\times26个z\)。发现\(26^3\)已经大于\(n\),所以我们只需要询问到这里。那么这两个字符串有什么用?在第二个字符串里,如果\(s_i\)变成了\(s_j\),那么说明其交换到了第\(s_j - 'a'\)个部分。但这两个信息依然无法确定位置,因为还有很多第二个字符串。那么经过第三个字符串的询问后,我们就可以知道是在哪一个第二个字符串的部分里。
点击查看代码
void solve() {
std::string s;
std::cin >> s;
int n = s.size();
auto ask = [&](const std::string & s) -> std::vector<int> {
std::cout << "? " << s << std::endl;
std::string t;
std::cin >> t;
std::vector<int> res(n);
for (int i = 0; i < n; ++ i) {
res[i] = t[i] - 'a';
}
return res;
};
std::string q1, q2, q3;
for (int i = 0; i < n; ++ i) {
q1 += (char)(i % 26 + 'a');
q2 += (char)(i / 26 % 26 + 'a');
q3 += (char)(i / 26 / 26 % 26 + 'a');
}
auto p1 = ask(q1);
auto p2 = ask(q2);
auto p3 = ask(q3);
std::string ans(n, ' ');
for (int i = 0; i < n; ++ i) {
ans[p3[i] * 26 * 26 + p2[i] * 26 + p1[i]] = s[i];
}
std::cout << "! " << ans << std::endl;
}

浙公网安备 33010602011771号