VP Educational Codeforces Round 53 (Rated for Div. 2)
A. Diverse Substring
看能不能选两个不一样的字符。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::string s;
std::cin >> s;
if (std::ranges::count(s, s[0]) == n) {
std::cout << "NO\n";
return;
}
std::cout << "YES\n";
std::string ans;
ans += s[0];
for (auto & c : s) {
if (c != s[0]) {
ans += c;
break;
}
}
std::cout << ans << "\n";
}
B. Vasya and Books
按题意模拟。用一个指针记录用到了\(b\)数组哪个位置。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::set<int> s;
std::vector<int> a(n), b(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
s.insert(a[i]);
}
for (int i = 0; i < n; ++ i) {
std::cin >> b[i];
}
for (int i = 0, j = 0; i < n; ++ i) {
if (!s.count(b[i])) {
std::cout << 0 << " \n"[i == n - 1];
} else {
int ans = 0;
while (a[j] != b[i]) {
s.erase(a[j]);
++ j;
++ ans;
}
s.erase(b[i]);
++ j;
std::cout << ans + 1 << " \n"[i == n - 1];
}
}
}
C. Vasya and Robot
题意:给你一个上下左右的移动序列,你需要选一个子区间任意更改,使得最后位置在\((x, y)\)。求最短的子区间。
任意更改,可以改也可以不改,那么如果短区间可以操作,那么长区间也可以。考虑二分。
通过前缀和维护,然后二分区间长度,对于每个区间可以求出除了它后剩下可以操作到哪里,然后得到横纵坐标差了多少,这个差的值不能超过区间长度,同时操作完后剩下的操作数不能是奇数。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::string s;
std::cin >> s;
int tx, ty;
std::cin >> tx >> ty;
std::vector<int> 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;
}
}
if (prex[n] == tx && prey[n] == ty) {
std::cout << 0 << "\n";
return;
}
auto check = [&](int len) -> bool {
for (int i = 1; i + len - 1 <= n; ++ i) {
int j = i + len - 1;
int dx = prex[i - 1] + prex[n] - prex[j];
int dy = prey[i - 1] + prey[n] - prey[j];
int d = std::abs(dx - tx) + std::abs(dy - ty);
if (d <= len && (len - d) % 2 == 0) {
return true;
}
}
return false;
};
int l = 1, r = n;
while (l < r) {
int mid = l + r >> 1;
if (check(mid)) {
r = mid;
} else {
l = mid + 1;
}
}
if (!check(l)) {
std::cout << -1 << "\n";
return;
}
std::cout << l << "\n";
}
D. Berland Fair
题意:一个人在一个环上依次买东西,直到它买不到任何东西为止。求能买多少东西。
模拟。每次模拟一遍把能拿的拿了,然后直接求出能拿几轮。然后减去。
模拟次数很少。
点击查看代码
void solve() {
int n;
i64 m;
std::cin >> n >> m;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
i64 ans = 0;
while (1) {
i64 sum = 0, cnt = 0;
for (int i = 0; i < n; ++ i) {
if (sum + a[i] <= m) {
sum += a[i];
++ cnt;
}
}
if (sum == 0) {
break;
}
ans += m / sum * cnt;
m -= m / sum * sum;
}
std::cout << ans << "\n";
}
E. Segment Sum
题意:求\([l, r]\)里不同数不超过\(k\)个的数的个数。
明显的数位\(dp\)。
记\(f[i][j][l][r]\)为到第\(i\)位,状态为\(j\),有没有前导零,有没有限制的答案。\(j\)是二进制数,每一位代表这个数有没有出现过。
但发现可能有很多数满足某个状态,导致无法计算所有状态。考虑把他们合并,用\(g[i][j][l][r]\)表示这个状态后续合法的数字个数,那么\(f[i][j][l][r] = \sum_{x=0}^{9} x \times 10^i \times g[i - 1][j'][l'][r'], g[i][j][l][r] = \sum_{x=0}^{9} g[i-1][j'][l'][r']\)。
点击查看代码
const int mod = 998244353;
int f[20][1024][2][2];
int g[20][1024][2][2];
void solve() {
i64 l, r;
int k;
std::cin >> l >> r >> k;
std::vector<int> P(20);
P[0] = 1;
for (int i = 1; i < 20; ++ i) {
P[i] = P[i - 1] * 10ll % mod;
}
auto add = [&](int & x, const int & y) {
x += y;
if (x >= mod) {
x -= mod;
}
};
auto dp = [&](i64 n) -> int {
std::string s = std::to_string(n);
std::ranges::reverse(s);
memset(f, -1, sizeof f);
memset(g, -1, sizeof g);
auto dfs = [&](auto & self, int u, int state, int zero, int limit) -> std::pair<int, int> {
if (u < 0) {
return {0, __builtin_popcount(state) <= k};
}
if (f[u][state][zero][limit] != -1) {
return {f[u][state][zero][limit], g[u][state][zero][limit]};
}
f[u][state][zero][limit] = g[u][state][zero][limit] = 0;
int up = limit ? s[u] - '0' : 9;
for (int i = 0; i <= up; ++ i) {
int nstate = zero && i == 0 ? state : (state | (1 << i));
auto next = self(self, u - 1, nstate, zero && i == 0, limit && i == up);
add(f[u][state][zero][limit], next.first);
add(f[u][state][zero][limit], 1ll * P[u] * i % mod * next.second % mod);
add(g[u][state][zero][limit], next.second);
}
return {f[u][state][zero][limit], g[u][state][zero][limit]};
};
dfs(dfs, (int)s.size() - 1, 0, 1, 1);
return f[(int)s.size() - 1][0][1][1];
};
std::cout << (dp(r) - dp(l - 1) + mod) % mod << "\n";
}