VP Educational Codeforces Round 44 (Rated for Div. 2)
A. Chess Placing
题意:一个长度为\(n\)的数组上有\(n / 2\)个点,你想要移动这些点使得它们的位置奇偶性相同,求最小移动数。
只有两种情况,要么在偶数位置要么在奇数位置,判断两种情况就行。
具体就是从小到大看,拿最小的位置移动到需要移动到的最小位置。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n / 2);
for (int i = 0; i < n / 2; ++ i) {
std::cin >> a[i];
}
std::ranges::sort(a);
int ans1 = 0, ans2 = 0;
for (int i = 1, j = 0; i <= n; i += 2, j += 1) {
ans1 += std::abs(i - a[j]);
}
for (int i = 2, j = 0; i <= n; i += 2, j += 1) {
ans2 += std::abs(i - a[j]);
}
std::cout << std::min(ans1, ans2) << "\n";
}
B. Switches and Lamps
题意:有一个\(n \times m\)的01矩阵,你需要删去一行,使得每一列至少有一个1。
枚举这个行即可。
点击查看代码
void solve() {
int n, m;
std::cin >> n >> m;
std::vector<std::string> s(n);
for (int i = 0; i < n; ++ i) {
std::cin >> s[i];
}
std::vector<int> cnt(m);
for (int i = 0; i < n; ++ i) {
for (int j = 0; j < m; ++ j) {
cnt[j] += s[i][j] == '1';
}
}
for (int i = 0; i < n; ++ i) {
bool flag = true;;
for (int j = 0; j < m; ++ j) {
flag &= cnt[j] - (s[i][j] == '1') > 0;
}
if (flag) {
std::cout << "YES\n";
return;
}
}
std::cout << "NO" << "\n";
}
C. Liebig's Barrels
题意:给你\(n\times k\)个数,你要把他们分成\(n\)组,每组的价值是其中的最小值,且每组的价值相差不超过\(l\)。
贪心的想,我们应该让每组的最小值最大。那么我们先排序。
然后找到和\(a_1\)的差小于等于\(l\)的最后一个位置,记为\(p\),那么我们要在\([1, p]\)这些位置里选\(n\)个出来作为最小值。
那么我们从\(p\)开始取,后面有\(n\times k - p\)个数可以分配给前面的数,记为\(cnt\)。那么如果\(cnt \geq k - 1\),我们就可以让\(a_i\)作为最小值。否则我们需要拿前面的数来凑。
点击查看代码
void solve() {
int n, k, l;
std::cin >> n >> k >> l;
int m = n * k;
std::vector<int> a(m);
for (int i = 0; i < m; ++ i) {
std::cin >> a[i];
}
std::ranges::sort(a);
int p = 0;
while (p + 1 < m && a[p + 1] - a[0] <= l) {
++ p;
}
if (p < n - 1) {
std::cout << 0 << "\n";
return;
}
i64 ans = 0;
for (int i = p, cnt = m - p - 1; i >= 0;) {
if (cnt >= k - 1) {
ans += a[i];
-- i;
cnt -= k - 1;
} else {
int d = k - 1 - cnt;
cnt = 0;
i -= d;
ans += a[i];
-- i;
}
}
std::cout << ans << "\n";
}
D. Sand Fortress
题意:你有\(n\)个数,和一个无限大的数组,你要每组,\(|a_i - a_{i-1}| \leq 1\),\(a_1 \leq h\),且\(\sum a_i = n\),求满足这些条件的情况下,\(a_i > 0\)的\(i\)数量最小是多少
首先观察一下,可以看出放的最后一个数是1,并且如果最大的\(a_i = k\),那么\([1, k]\)里的数都至少出现一次,因为相邻两个数小于等于1,那么\(k\)想要都1,则中间的数都得出现过。
然后一个贪心思想是,\(k\)越大那么大于0的位置就越小。
于是我们二分这个\(k\),找到可行的最大的\(k\),然后求出它的答案。
\(check\)里需要进行分类讨论,如果\(k>h\),则需要先从\(h\)到\(k\),然后我们构造一个\(k\)到\(1\)的等差序列,如果这些数的和大于\(n\)则不可行。最小剩下的值就都拿去凑\(k\),直到小于\(k\)。
点击查看代码
void solve() {
i64 n, h;
std::cin >> n >> h;
auto check = [&](i64 x) -> std::pair<bool, i64> {
i128 sum = 0;
i64 len = 0;
if (x > h) {
sum += (i128)(x - h) * (h + x - 1) / 2;
len += x - h;
}
if ((i128)x * (x + 1) / 2 + sum > n) {
return {false, 0};
}
i64 m = n - sum - (i128)x * (x + 1) / 2;
return {true, len + x + (m + x - 1) / x};
};
i64 l = 1, r = n;
while (l < r) {
i64 mid = l + r + 1 >> 1ll;
if (check(mid).first) {
l = mid;
} else {
r = mid - 1;
}
}
std::cout << check(l).second << "\n";
}
E. Pencils and Boxes
题意:给你\(n\)个数,你要把他们分成若干个集合,每个集合至少有\(m\)个数,并且每个集合的极差不超过\(d\)。
先进行排序。
那么每个集合一定是选一些连续的数,因为如果我们选了一些连续的数,然后把这个数分给其它集合,则会导致其它集合的极差变大,显然不优。
那么考虑\(dp\),记\(f_i\)表示以\(i\)结尾选了大于等于\(m\)个数是否可行。
那么我们需要找一个\(j, j < i\),使得\(f_{j-1}\)为1,并且\(i - j + 1 \geq m, a_i - a_j \leq d\)。如果直接暴力找显然超时,可以转换思路,对于每个\(i\)找一个\(j, j > i\),且\(f_{i-1}\)为1,\(j - i + 1 \geq m, a_j - a_i \leq d\)。那么显然如果有\(i' < i\),则\(i'\)可以转移到的\(j\),\(i\)也可以转移到,于是我们记录一个指针\(j\),每次右移动。
点击查看代码
void solve() {
int n, m, d;
std::cin >> n >> m >> d;
std::vector<int> a(n + 1);
for (int i = 1; i <= n; ++ i) {
std::cin >> a[i];
}
std::ranges::sort(a);
std::vector<int> f(n + 1);
f[0] = 1;
for (int i = 1, j = 1; i <= n; ++ i) {
if (f[i - 1]) {
j = std::max(j, i + m - 1);
while (j <= n && a[j] - a[i] <= d) {
f[j] = 1;
++ j;
}
}
}
if (f[n]) {
std::cout << "YES\n";
} else {
std::cout << "NO\n";
}
}
F. Isomorphic Strings
题意:给你一个字符串,每次求两个长度相等的子串是不是同构的。两个字符串同构,则可以把第一个字符串的某些字符替换为另一个字符串的某个字符,使得和另一个字符串相等。
如果一个字符可以和另一个字符匹配,那么它们它们出现的位置是相同的,则我们可以用26个二进制串来表示每个字符,如果某一位为1代表这个字符在这一位出现过。那么我们把两个字符串的26个二进制串的hash值拿出来比较看是不是一样。
点击查看代码
struct Hash {
const int mod1 = 1e9 + 7, mod2 = 998244353;
const int base1 = 131, base2 = 13331;
std::array<std::vector<int>, 26> h1, h2, p1, p2;
Hash() {}
Hash(const std::string & s) {
init(s);
}
void init(const std::string & s) {
int n = s.size();
for (int i = 0; i < 26; ++ i) {
h1[i].resize(n + 1);
h2[i].resize(n + 1);
p1[i].resize(n + 1);
p2[i].resize(n + 1);
h1[i][0] = h2[i][0] = 0;
p1[i][0] = p2[i][0] = 1;
for (int j = 0; j < n; ++ j) {
h1[i][j + 1] = 1LL * h1[i][j] * base1 % mod1 + (s[j] - 'a' == i) + 1;
h2[i][j + 1] = 1LL * h2[i][j] * base2 % mod2 + (s[j] - 'a' == i) + 1;
p1[i][j + 1] = 1LL * p1[i][j] * base1 % mod1;
p2[i][j + 1] = 1LL * p2[i][j] * base2 % mod2;
}
}
}
int get1(int l, int r, int ch) {
return (h1[ch][r] - 1LL * h1[ch][l - 1] * p1[ch][r - l + 1] % mod1 + mod1) % mod1;
}
int get2(int l, int r, int ch) {
return (h2[ch][r] - 1LL * h2[ch][l - 1] * p2[ch][r - l + 1] % mod2 + mod2) % mod2;
}
};
void solve() {
int n, q;
std::cin >> n >> q;
std::string s;
std::cin >> s;
Hash hash(s);
while (q -- ) {
int x, y, len;
std::cin >> x >> y >> len;
std::vector<std::pair<int, int>> a, b;
for (int i = 0; i < 26; ++ i) {
a.emplace_back(hash.get1(x, x + len - 1, i), hash.get2(x, x + len - 1, i));
b.emplace_back(hash.get1(y, y + len - 1, i), hash.get2(y, y + len - 1, i));
}
std::ranges::sort(a);
std::ranges::sort(b);
if (a == b) {
std::cout << "YES\n";
} else {
std::cout << "NO\n";
}
}
}