VP Educational Codeforces Round 48 (Rated for Div. 2)
A. Death Note
点击查看代码
void solve() {
int n, m;
std::cin >> n >> m;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
for (int i = 0, last = 0; i < n; ++ i) {
last += a[i];
std::cout << last / m << " \n"[i == n - 1];
last %= m;
}
}
B. Segment Occurrences
题意:给你两个字符串\(s, t\),\(q\)次询问\(s\)的子串\(l, r\)里\(t\)出现几次。
前缀和预处理第\(i\)个位置的前缀\(t\)出现几次。
点击查看代码
void solve() {
int n, m, q;
std::cin >> n >> m >> q;
std::string s, t;
std::cin >> s >> t;
std::vector<int> sum(n + 1);
for (int i = 0; i < n; ++ i) {
sum[i + 1] = sum[i] + (s.substr(i, m) == t);
}
while (q -- ) {
int l, r;
std::cin >> l >> r;
if (r - l + 1 < m) {
std::cout << 0 << "\n";
continue;
}
std::cout << sum[r - m + 1] - sum[l - 1] << "\n";
}
}
C. Vasya And The Mushrooms
题意:一个\(2\times n\)的矩阵,你从左上角出发,需要不重不漏的走完整个矩阵,如果第\(d\)步走到\((i, j)\)可以得到\(d \times a[i][j]\)的价值,求最大价值。
发现路径一定是上下两行切换一段后,一直往右走到\(n\),然后走到另一行一直往左。那么外面预处理后缀,\(sum1_i\)表示从\((1, i)\)一直向右然后向下再向左到\((2, i)\)的价值,\(sum2_i\)表示从\((2, i)\)到\((1, i)\)的价值,那么\(sum1_i = 2\times (i - 1) \times a[1][i] + (n + m - 1) \times a[2][i] + sum1_{i+1} - suf\),其中\(suf\)表示\(i\)后面的两行所有元素的和,\(sum2\)的转移同理。
那么外面就可以枚举前缀走上下两行的路径走到哪里,然后加上后面的价值。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector a(2, std::vector<int>(n));
for (int i = 0; i < 2; ++ i) {
for (int j = 0; j < n; ++ j) {
std::cin >> a[i][j];
}
}
std::vector<i64> sum1(n + 1), sum2(n + 1);
i64 suf = 0;
for (int i = n - 1; i >= 0; -- i) {
sum1[i] = sum1[i + 1] - suf;
sum1[i] += (i64)(2 * i) * a[0][i] + (i64)(2 * n - 1) * a[1][i];
suf += a[0][i] + a[1][i];
}
suf = 0;
for (int i = n - 1; i >= 0; -- i) {
sum2[i] = sum2[i + 1] - suf;
sum2[i] += (i64)(2 * n - 1) * a[0][i] + (i64)(2 * i) * a[1][i];
suf += a[0][i] + a[1][i];
}
i64 ans = sum1[0], pre = 0;
for (int i = 0, d = 0; i < n; ++ i) {
if (i % 2 == 0) {
pre += (i64)d * a[0][i];
++ d;
pre += (i64)d * a[1][i];
++ d;
ans = std::max(ans, pre + sum2[i + 1]);
} else {
pre += (i64)d * a[1][i];
++ d;
pre += (i64)d * a[0][i];
++ d;
ans = std::max(ans, pre + sum1[i + 1]);
}
}
std::cout << ans << "\n";
}
D. Vasya And The Matrix
题意:你需要构造一个\(n\times m\)的矩阵,使得第\(i\)行的异或和为\(a_i\),第\(j\)列的异或和为\(b_j\)。
首先\(a\)的异或和就是所有元素的异或和,同理\(b\)的异或和也是所有元素的异或和,所以先比较这两个相不相等。
然后可以把\(a_1\)到\(a_{n-1}\)依次给每行的最后一个元素,\(b_1\)到\(b_{m-1}\)依次给每列的最后一个元素,这样我们只有第\(n\)行第\(m\)列没有满足了,可以先算出来满足一个的值,判断和另一个是不是相等。
点击查看代码
void solve() {
int n, m;
std::cin >> n >> m;
std::vector<int> a(n), b(n);
int suma = 0;
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
suma ^= a[i];
}
int sumb = 0;
for (int i = 0; i < m; ++ i) {
std::cin >> b[i];
sumb ^= b[i];
}
if (suma != sumb) {
std::cout << "NO\n";
return;
}
std::vector ans(n, std::vector<int>(m));
for (int i = 0; i + 1 < m; ++ i) {
ans[n - 1][i] = b[i];
}
for (int i = 0; i + 1 < n; ++ i) {
ans[i][m - 1] = a[i];
}
ans[n - 1][m - 1] = (suma ^ a[n - 1]) ^ b[m - 1];
if ((ans[n - 1][m - 1] ^ sumb ^ b[m - 1]) != a[n - 1]) {
std::cout << "NO\n";
return;
}
std::cout << "YES\n";
for (int i = 0; i < n; ++ i) {
for (int j = 0; j < m; ++ j) {
std::cout << ans[i][j] << " \n"[j == m - 1];
}
}
}