VP Toyota Programming Contest 2024#11(AtCoder Beginner Contest 379)
A - Cyclic
题意:按题意输出三个字符。
点击查看代码
void solve() {
std::string s;
std::cin >> s;
std::cout << s[1] << s[2] << s[0] << " " << s[2] << s[0] << s[1] << "\n";
}
B - Strawberries
题意:题意,每连续的\(k\)个'O'可以得一分,最多得几分。
枚举计数即可。
点击查看代码
void solve() {
int n, k;
std::cin >> n >> k;
std::string s;
std::cin >> s;
int ans = 0;
for (int i = 0; i < n; ++ i) {
if (s[i] == 'O') {
int j = i;
while (j < n && s[j] == 'O') {
++ j;
}
ans += (j - i) / k;
i = j;
}
}
std::cout << ans << "\n";
}
C - Sowing Stones
题意:要在\([1, n]\)每个格子铺上正好一个石头,有\(m\)格格子各有一些石头,每次可以移动一个石头到下一格,问最少操作次数。
从左到右模拟,每次把多出来的石头都移过来,操作数就是一个等差序列的和。最后判断是不是刚好铺满就行。
点击查看代码
void solve() {
int n, m;
std::cin >> n >> m;
std::vector<i64> a(m), b(m);
for (int i = 0; i < m; ++ i) {
std::cin >> a[i];
}
for (int i = 0; i < m; ++ i) {
std::cin >> b[i];
}
std::vector<int> id(m);
std::iota(id.begin(), id.end(), 0);
std::sort(id.begin(), id.end(), [&](int i, int j) {
return a[i] < a[j];
});
a.push_back(n);
i64 last = 0, sum = 0;
i64 ans = 0;
for (auto & i : id) {
if (a[i] - last - 1 > sum) {
std::cout << -1 << "\n";
return;
}
ans += (a[i] - last) * (sum + sum - (a[i] - last) + 1) / 2;
sum -= a[i] - last - 1;
sum += b[i] - 1;
last = a[i];
}
if (n - last != sum) {
std::cout << -1 << "\n";
return;
}
ans += (n - last) * (sum + sum - (n - last) + 1) / 2;
std::cout << ans << "\n";
}
D. Home Garden
题意:三个操作:
- 种下一颗树,初始高度为\(0\)。
- 等待\(t\)天。所有树长高\(t\)。
- 收割高度大于等于\(k\)的树。
用一个队列模拟即可,每次种树是加入一个高度为当前时间的树,然后收割的时候把所有当前时间减记录的高度大于等于\(k\)的出队就行。
点击查看代码
void solve() {
int n;
std::cin >> n;
i64 t = 0;
std::queue<i64> q;
while (n -- ) {
int op;
std::cin >> op;
if (op == 1) {
q.push(t);
} else if (op == 2) {
int x;
std::cin >> x;
t += x;
} else if (op == 3) {
int h;
std::cin >> h;
int ans = 0;
while (q.size() && t - q.front() >= h) {
++ ans;
q.pop();
}
std::cout << ans << "\n";
}
}
}
E - Sum of All Substrings
题意:给你一个大数字,求它所有字串表示数字的和。
拆贡献,考虑每一位的贡献,发现第\(i\)个数字可以当个位,如果后面还有数可以当十位,那么最多可以当\(n-i+1\)为,每一位都有\(i\)种取值方式,所有第\(i\)个数字的贡献就是\(\sum_{j=0}^{n-i} i \times s_i * 10^{j}\),可以用差分处理每一位需要加的数,最后模拟一下高精度就行。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::string s;
std::cin >> s;
std::vector<i64> d(n + 11);
for (int i = 0; i < n; ++ i) {
i64 t = (i64)(i + 1) * (s[i] - '0');
d[1] += t;
d[n - i + 1] -= t;
}
for (int i = 1; i <= n + 10; ++ i) {
d[i] += d[i - 1];
}
std::vector<i64> ans;
for (int i = 1; i <= n + 10; ++ i) {
ans.push_back(d[i] % 10);
d[i + 1] += d[i] / 10;
}
while (ans.size() > 1 && ans.back() == 0) {
ans.pop_back();
}
std::reverse(ans.begin(), ans.end());
for (auto & x : ans) {
std::cout << x;
}
std::cout << "\n";
}
F - Buildings 2
题意:给你一个数组,每次询问\(i \in [r + 1, n]\)的每个\(i\), \(a_i >= \max_{j=l+1}^{i-1} a_j\)的\(i\)的个数。
如果是询问\(i\)右边大于等于\(\max_{j=i+1}^{j-1} a_j\)的位置有多少个,如何做?可以从后往前,用树状数组或者单调栈都可以。
现在的条件就是加了一个位置要大于\(r\),那么一样可以用单调栈,每次二分一些有多少位置大于\(r\)就行了,也可以用树状数组维护,相当于多了一个维度,类似二维偏序。
点击查看代码
void solve() {
int n, q;
std::cin >> n >> q;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
std::vector<std::vector<std::pair<int, int> > > Q(n);
std::vector<int> ans(q);
for (int i = 0; i < q; ++ i) {
int l, r;
std::cin >> l >> r;
-- l, -- r;
Q[l].push_back({r, i});
}
std::vector<int> stk;
for (int i = n - 1; i >= 0; -- i) {
for (auto & [j, id] : Q[i]) {
int l = 0, r = (int)stk.size() - 1;
while (l < r) {
int mid = l + r + 1>> 1;
if (stk[mid] > j) {
l = mid;
} else {
r = mid - 1;
}
}
if (stk[l] <= j) {
ans[id] = 0;
} else {
ans[id] = l + 1;
}
}
while (stk.size() && a[stk.back()] < a[i]) {
stk.pop_back();
}
stk.push_back(i);
}
for (int i = 0; i < q; ++ i) {
std::cout << ans[i] << "\n";
}
}