AtCoder Regular Contest 153
A - AABCDDEFE (arc153 a)
题目大意
给定一个仅包含数字的字符串,称它为好的,当且仅当其包含\(9\)个数字,且
- \(s_1 \neq 0\)
- \(s_1 = s_2\)
- \(s_5 = s_6\)
- \(s_7 = s_9\)
给定\(N\),问字符串第 \(N\)小的好串。
解题思路
自由位置其实只有\(s_1,s_3,s_4,s_5,s_7,s_8\)六个,因此可以预处理这\(10^6\)个,或者将\(N\)每位拆解赋值到对应位置即可。
神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
LL n;
cin >> n;
-- n;
vector<int> qwq;
while(n){
qwq.push_back(n % 10);
n /= 10;
}
string s(9, '0');
s[0] = '1';
s[1] = '1';
if (qwq.size() > 0)
s[7] += qwq[0];
if (qwq.size() > 1){
s[6] += qwq[1];
s[8] += qwq[1];
}
if (qwq.size() > 2){
s[4] += qwq[2];
s[5] += qwq[2];
}
if (qwq.size() > 3){
s[3] += qwq[3];
}
if (qwq.size() > 4){
s[2] += qwq[4];
}
if (qwq.size() > 5){
s[1] += qwq[5];
s[0] += qwq[5];
}
cout << s << '\n';
return 0;
}
B - Grid Rotations (arc153 b)
题目大意
给定一个\(h\times w\)的网格,进行 \(q\)次操作,每次操作包含两个数\(x,y\),将网格分成四部分,其中左上部分的右下角为 \(x,y\),然后对四个部分分别旋转180度。
问 \(q\)次操作的网格图样子。
解题思路
考虑一维的情况,比如 1 2 3 4 5 6
,我们将头尾视为相连,即\(1\)的左边是 \(6\)。假定选择一个位置进行翻转,比如选择 4
,就变成4 3 2 1 6 5
,观察1
左右两边的数,始终都是 2,6
,只是左右方向变了,其他数亦是如此。
因此将头尾连成一个环形关系,每次操作都不会改变该环形关系,只是左右对调了。
拓展到二维的话,就是将上下相连,左右相连,形成一个球形关系,每次操作同样不会改变这个球形关系,只是上下交换,左右交换了。
因此我们只要处理出一个位置经过\(q\)次操作后的位置,然后再根据原来的球形关系还原出答案即可。
神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int h, w;
cin >> h >> w;
vector<string> s(h);
for(auto &i : s){
cin >> i;
}
int sx = 0, sy = 0;
auto change = [&](int x, int y){
if (sx <= x){
int rh = x + 1;
sx = rh - sx - 1;
}else {
int rh = h - x - 1;
sx -= x + 1;
sx = rh - sx - 1;
sx += x + 1;
}
if (sy <= y){
int rw = y + 1;
sy = rw - sy - 1;
}else {
int rw = w - y - 1;
sy -= y + 1;
sy = rw - sy - 1;
sy += y + 1;
}
};
int q;
cin >> q;
int dir = -2 * (q & 1) + 1;
while(q--){
int x, y;
cin >> x >> y;
-- x, --y;
change(x, y);
}
vector<vector<char>> ans(h, vector<char>(w));
for(int i = 0; i < h; ++ i){
for(int j = 0; j < w; ++ j){
ans[sx][sy] = s[i][j];
sy = (sy + w + dir) % w;
}
sx = (sx + h + dir) % h;
}
for(auto &i : ans){
for(auto &j : i)
cout << j;
cout << '\n';
}
return 0;
}
C - ± Increasing Sequence (arc153 c)
题目大意
给定一个长度为\(n\),仅包含\(-1,1\)的数组 \(a\)。要求构造一个长度一样为\(n\)的数组\(x\),满足
- \(|x_i| \leq 10^{12}\)
- 数组\(x\)严格递增
- \(\sum_{i=1}^{n} a_i x_i = 0\)
不存在则告知该事实。
解题思路
想的很朴素,就是先填充\(x\)为 \(1,2,3,...,n\)。然后计算下 \(sum = \sum a_i x_i\)的值。
- 如果 \(sum = 0\)就皆大欢喜。
- 如果 \(sum < 0\),就找一个数组\(a\)前缀和为\(-1\)的下标 \(pos\),则 \(x_i -= 1, i \in [1,pos]\) ,\(sum\)的值就会 \(+1\)。因此令 \(x_i -= (-sum), i \in [1, pos]\) ,这样\(sum\)就变成 \(0\)了,同时还保证了递增条件。因为\(|sum| \leq n^2 = 10^{10}\),因此\(x_i\)不会 超出范围。
- 如果 \(sum > 0\),就找一个数组\(a\)前缀和为\(1\)的下标 \(pos\),则 \(x_i -= 1, i \in [1,pos]\) ,\(sum\)的值就会 \(-1\)。因此令 \(x_i -= (sum), i \in [1, pos]\) ,这样\(sum\)就变成 \(0\)了。同时还保证了递增条件。因为\(|sum| \leq n^2 = 10^{10}\),因此\(x_i\)不会 超出范围。
如果找不到对应的下标,就无解了(应该指这类初始情况的填法无解,因为初始严格递增的填法限制了改动范围只能是个前缀或后缀,但不清楚能否对应原问题的无解)(原本还想着倒着找个后缀和+1的,但过了)被评论区数据hack了,加上了这个判断。
因为\(a\)只有 \(1\)和 \(-1\),所以其前缀和相邻项最多相差 \(1\),第一个大于 \(0\)的必然是 \(1\),反之也是 \(-1\)。
神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n;
cin >> n;
vector<LL> a(n);
vector<LL> sufa(n);
vector<LL> prea(n);
for(auto &i : a)
cin >> i;
vector<LL> ans(n);
LL st = 1;
iota(ans.begin(), ans.end(), st);
LL sum = 0;
for(int i = 0; i < n; ++ i)
sum += ans[i] * a[i];
partial_sum(a.begin(), a.end(), prea.begin());
partial_sum(a.rbegin(), a.rend(), sufa.rbegin());
auto solve = [&](){
if (sum == 0)
return true;
if (sum < 0){
for(auto &i : prea)
i *= -1;
for(auto &i : sufa)
i *= -1;
sum *= -1;
}
int pos = 0;
for(; pos < n; ++ pos)
if (prea[pos] > 0)
break;
if (pos == n){
for(pos = n - 1; pos >= 0; -- pos)
if (sufa[pos] < 0)
break;
if (pos == -1)
return false;
for(int i = n - 1; i >= pos; -- i)
ans[i] += sum;
return true;
}else{
for(int i = 0; i <= pos; ++ i){
ans[i] -= sum;
}
return true;
}
};
if (solve()){
cout << "Yes" << '\n';
for(auto &i : ans)
cout << i << ' ';
cout << '\n';
}else{
cout << "No" << '\n';
}
return 0;
}
D - Sum of Sum of Digits (arc153 d)
题目大意
给定一个长度为\(n\)的数组\(a\),要求找到一个 \(x\),使得 \(\sum_{i=1}^{n}f(a_i + x)\)最小,其中 \(f(x)\)表示 \(x\)在十进制下各个数字的和,比如 \(f(1223) = 1 + 2 + 2 + 3 = 8\)
输出该最小值。
解题思路
<++>
神奇的代码
E - Deque Minimization (arc153 e)
题目大意
<++>
解题思路
<++>
神奇的代码
F - Tri-Colored Paths (arc153 f)
题目大意
<++>
解题思路
<++>
神奇的代码