Rayan Programming Contest 2024 - Selection (Codeforces Round 989, Div. 1 + Div. 2) 补题记录(A~E)
1.CodeForces Round #939(Div. 2) 补题记录(A~F)2.CodeTON Round 8 (Div. 1 + Div. 2, Rated, Prizes!) 补题记录(A~A)3.Educational Codeforces Round 163 (Rated for Div. 2) 补题记录(A~D)4.CodeForces Round #951(Div. 2) 补题记录(A~E)5.Codeforces Global Round 26 补题记录(A~C2)6.CodeForces Round #959 sponsored by NEAR (Div. 1 + Div. 2) 补题记录(A~E)7.Codeforces Round 960 (Div. 2) 补题记录(A~D)8.Codeforces Round 961 (Div. 2) 补题记录(A~D)9.Codeforces Round 962 (Div. 3) 补题记录(A~G)10.Pinely Round 4 (Div. 1 + Div. 2) 补题记录(A~F)11.Educational Codeforces Round 168 (Rated for Div. 2) 补题记录(A~E)12.Codeforces Round 963 (Div. 2) 补题记录(A~D,F1)13.Codeforces Round 964 (Div. 4) 补题记录(A~G2)14.Codeforces Round 965 (Div. 2) 补题记录(A,B,D,E1)15.EPIC Institute of Technology Round August 2024 (Div. 1 + Div. 2) 补题记录(A~D1,E)16.Educational Codeforces Round 169 (Rated for Div. 2) 补题记录(A~F)17.Codeforces Round 972 (Div. 2) 补题记录(A~C,E1)18.Codeforces Round 988 (Div. 3) 补题记录(A~G)
19.Rayan Programming Contest 2024 - Selection (Codeforces Round 989, Div. 1 + Div. 2) 补题记录(A~E)
A
答案显然就是 \(\text{lcm}(a,b)\)。
void run() {
int T = read();
while (T--) {
int a = read(), b = read();
cout << a / __gcd(a, b) * b << '\n';
}
}
B
考虑贪心模拟。若当前枚举到位置 \(i\) 时恰有 \(m\) 个连续的 \(0\),则从这个位置开始将后面连续的 \(k\) 个位置全部赋值为 \(1\)。容易证明这是正确的。
时间复杂度为 \(O(n)\)。
char s[N];
void run() {
int T = read();
while (T--) {
int n = read(), m = read(), k = read();
scanf("%s", s + 1);
int cnt = 0, sum = 0;
for (int i = 1; i <= n; ++i) {
if (s[i] == '0') {
++cnt;
if (cnt >= m) {
++sum;
int j, x;
for (j = i, x = 1; j <= n && x <= k; ++j, ++x)
s[j] = '1';
i = j - 1;
cnt = 0;
}
} else {
cnt = 0;
}
}
cout << sum << '\n';
}
}
C
考虑这样的一个策略:
- 若存在一个只包含
?
的四连通块满足该块内?
的数目不小于 \(2\),则考虑任选两个相邻的?
并让它们互相只想对方,其余的?
都指向这两个?
中的一个。 - 若某一个
?
四联通的某一个位置不是?
,且从该位置出发会无限循环,则让这个?
指向这个位置。 - 剩下的位置随便指向任意一个位置。
容易证明该策略正确。若把指向关系显示建图则形成一个基环森林,维护的话可以使用并查集和 dfs 找环。总时间复杂度为 \(O(\alpha nm)\)。
代码可能有点难写。
char s[2010][2010];
int id[2010][2010], fa[N], fm[N];
int find(int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
const int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};
int vis[2010][2010], n, m, dfn;
int dfs(int x, int y) {
assert(s[x][y] != '?');
if (x < 1 || y < 1 || x > n || y > m) return 0;
if (vis[x][y] == dfn)
return 1;
else if (vis[x][y] && fm[id[x][y]])
return 1;
else if (vis[x][y])
return 0;
vis[x][y] = dfn;
if (s[x][y] == 'U') {
if (dfs(x - 1, y)) {
fm[id[x][y]] = 1;
return 1;
}
}
if (s[x][y] == 'D') {
if (dfs(x + 1, y)) {
fm[id[x][y]] = 1;
return 1;
}
}
if (s[x][y] == 'L') {
if (dfs(x, y - 1)) {
fm[id[x][y]] = 1;
return 1;
}
}
if (s[x][y] == 'R') {
if (dfs(x, y + 1)) {
fm[id[x][y]] = 1;
return 1;
}
}
return 0;
}
void run() {
// freopen("1.in", "r", stdin);
// freopen("1.out", "w", stderr);
int T = read(), ca = 1;
while (T--) {
n = read(), m = read();
for (int i = 1; i <= n; ++i)
scanf("%s", s[i] + 1);
// if (ca++ == 41) {
// for (int i = 1; i <= n; ++i, cerr << '\n')
// for (int j = 1; j <= m; ++j) cerr << s[i][j];
// }
dfn = 0;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
if (s[i][j] == '?')
for (int d = 0; d < 4; ++d) {
int ii = i + dx[d], jj = j + dy[d];
if (ii >= 1 && ii <= n && jj >= 1 && jj <= m && s[ii][jj] == '?') {
if (d == 0) s[i][j] = 'R', s[ii][jj] = 'L';
else if (d == 2) s[i][j] = 'L', s[ii][jj] = 'R';
else if (d == 1) s[i][j] = 'D', s[ii][jj] = 'U';
else s[i][j] = 'U', s[ii][jj] = 'D';
break;
}
}
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
if (s[i][j] == '?')
for (int d = 0; d < 4; ++d) {
int ii = i + dx[d], jj = j + dy[d];
if (ii >= 1 && ii <= n && jj >= 1 && jj <= m) {
if (s[ii][jj] != '?') {
int ok = 0;
if (s[ii][jj] == 'L' && d == 0) s[i][j] = 'R', ok = 1;
else if (s[ii][jj] == 'R' && d == 2) s[i][j] = 'L', ok = 1;
else if (s[ii][jj] == 'U' && d == 1) s[i][j] = 'D', ok = 1;
else if (s[ii][jj] == 'D' && d == 3) s[i][j] = 'U', ok = 1;
if (ok) break;
}
}
}
// for (int i = 1; i <= n; ++i, cout << '\n')
// for (int j = 1; j <= m; ++j) cout << s[i][j];
int idx = 0;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j) {
++idx;
id[i][j] = idx;
fa[idx] = idx;
fm[idx] = 0;
vis[i][j] = 0;
}
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
if (s[i][j] != '?')
++dfn, dfs(i, j);
// for (int i = 1; i <= n; ++i, cout << '\n')
// for (int j = 1; j <= m; ++j) cout << s[i][j];
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
if (s[i][j] != '?') {
int ii, jj;
if (s[i][j] == 'L') ii = i, jj = j - 1;
else if (s[i][j] == 'R') ii = i, jj = j + 1;
else if (s[i][j] == 'U') ii = i - 1, jj = j;
else ii = i + 1, jj = j;
if (ii >= 1 && ii <= n && jj >= 1 && jj <= m) {
int x = find(id[i][j]), y = find(id[ii][jj]);
if (x != y) fm[y] |= fm[x], fa[x] = y;
}
}
// for (int i = 1; i <= n * m; ++i) cout << fm[i] << ' ';
// cout << '\n';
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
if (s[i][j] == '?')
for (int d = 0; d < 4; ++d) {
int ii = i + dx[d], jj = j + dy[d];
if (ii >= 1 && ii <= n && jj >= 1 && jj <= m) {
assert(s[ii][jj] != '?');
if (fm[find(id[ii][jj])]) {
if (d == 0) s[i][j] = 'R';
else if (d == 2) s[i][j] = 'L';
else if (d == 1) s[i][j] = 'D';
else s[i][j] = 'U';
int x = find(id[ii][jj]), y = find(id[i][j]);
if (x != y) fm[y] |= fm[x], fa[x] = y;
break;
}
}
}
int cnt = 0;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
cnt += fm[find(id[i][j])];
// for (int i = 1; i <= n; ++i, cout << '\n')
// for (int j = 1; j <= m; ++j) cout << s[i][j];
cout << cnt << '\n';
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j) {
id[i][j] = 0;
fa[idx] = 0;
s[i][j] = 0;
fm[idx] = 0;
vis[i][j] = 0;
}
}
}
D
比 C 简单。考虑用 set 来维护当前所有 \(0,1,2\) 的位置。每一次找到最后一个 \(0\) 和最前一个 \(1\)(需要满足最后一个 \(0\) 在最前一个 \(1\) 后面)或最后一个 \(2\) 和最前一个 \(1\)(需要满足最后一个 \(2\) 在最前一个 \(1\) 后面)交换。容易证明该策略正确。判断当前数组是否有序可以维护当前所有出现过的不同数字,然后用 set 找到当前数字最前和最后的位置就行了。
时间复杂度为 \(O(n\log n)\),自带大常数(雾
int a[N];
void run() {
int T = read(), ca = 1;
while (T--) {
int n = read();
for (int i = 1; i <= n; ++i)
a[i] = read();
set<int> buc[3];
for (int i = 1; i <= n; ++i)
if (a[i] == 0) buc[0].insert(i);
else if (a[i] == 1) buc[1].insert(i);
else buc[2].insert(i);
auto chk = [&](void) {
int cnt = 0;
vector<int> id;
for (int i = 0; i < 3; ++i)
if (buc[i].size()) ++cnt, id.eb(i);
if (cnt == 1) return 1;
else if (cnt == 2) {
if (*buc[id[0]].rbegin() < *buc[id[1]].begin()) return 1;
return 0;
} else {
if (*buc[0].rbegin() < *buc[1].begin() && *buc[1].rbegin() < *buc[2].begin()) return 1;
return 0;
}
};
vector<pair<int, int>> op;
while (!chk()) {
if (buc[0].size() && buc[1].size()) {
int x = *buc[0].rbegin(), y = *buc[1].begin();
if (x > y) {
op.eb(x, y);
buc[0].erase(x);
buc[1].erase(y);
buc[0].insert(y);
buc[1].insert(x);
}
}
if (chk()) break;
if (buc[1].size() && buc[2].size()) {
int x = *buc[1].rbegin(), y = *buc[2].begin();
if (x > y) {
op.eb(x, y);
buc[1].erase(x);
buc[2].erase(y);
buc[1].insert(y);
buc[2].insert(x);
}
}
}
cout << op.size() << '\n';
for (auto &[x, y] : op)
cout << x << ' ' << y << '\n';
}
}
E
大分类讨论。
- \(n=1\)。此时若 \(k=1\) 则需构造排列 \(\lbrace 1\rbrace\)。否则无解。
- \(n\neq 1\) 且 \(k=1\)。此时显然无解。
- \(2\mid k\)。先考虑 \(k=2\) 的特殊情况。显然可以构造 \(\lbrace 1,2,3,\ldots,n\rbrace\) 和 \(\lbrace n,n-1,n-2,\ldots,1\rbrace\)。同样的若 \(2\mid k\) 则可以构造 \(1\sim n\) 组成的排列中字典序前 \(\frac{k}{2}\) 小的排列和字典序前 \(\frac{k}{2}\) 的排列。特殊点,若 \(n!<k\) 则无解。
- \(k-1\mid n-1\)。此时令 \(d=\frac{n-1}{d-1}\),可以构造 \(k\) 个排列。其中第 \(i\) 个排列(\(i<k\))为 \(\lbrace 1+(d-1)i,2+(d-1)i,\ldots,n,1,2,\ldots,(d-1)i\rbrace\)。最后一个排列直接让每一个位置所对应元素的和相等即可。
- \(2\nmid n\)。此时考虑到 \(k\ge 3\) 且 \(2\nmid k\),所以考虑先用上面的方法构造 \(k=3\) 的排列,对于另外 \(n-3\) 个排列用偶数的构造方法。特殊的,若 \(n!+3<k\) 则无解。
- 其余情况无解。
时间复杂度为 \(O(nk)\),可以通过。
int sjh[N], p1[N], p2[N], n, k;
void run() {
int T = read(), ca = 1;
while (T--) {
n = read(), k = read();
if (n == 1) {
if (k == 1) {
cout << "YES\n";
for (int i = 1; i <= k; ++i) cout << "1\n";
} else {
cout << "NO\n";
}
} else if (k == 1) cout << "NO\n";
else if (~k & 1) {
int fac = 1;
if (n > 12) fac = LLONG_MAX;
else {
for (int i = 1; i <= n; ++i)
fac = fac * i;
}
if (fac < k) cout << "NO\n";
else {
cout << "YES\n";
iota(a + 1, a + n + 1, 1ll);
for (int i = 0; i < k / 2; ++i) {
for (int j = 0; j < n; ++j) cout << a[j + 1] << ' ';
cout << '\n';
next_permutation(a + 1, a + n + 1);
}
iota(a + 1, a + n + 1, 1ll);
reverse(a + 1, a + n + 1);
for (int i = 0; i < k / 2; ++i) {
for (int j = 0; j < n; ++j) cout << a[j + 1] << ' ';
cout << '\n';
prev_permutation(a + 1, a + n + 1);
}
}
} else {
if (n == k) {
cout << "YES\n";
for (int i = 1; i <= n; ++i, cout << '\n') {
int j = i;
for (int x = 1; x <= n; ++x) {
cout << j << ' ';
++j;
if (j > n) j = 1;
}
}
} else {
if ((n - 1) % (k - 1) == 0) {
cout << "YES\n";
for (int i = 0; i < n; ++i) sjh[i] = 0;
int dt = (n - 1) / (k - 1), st = 1;
while (k--) {
if (k) {
int x = st;
for (int i = 0; i < n; ++i) {
cout << x << ' ';
sjh[i] += x;
++x;
if (x > n) x = 1;
}
cout << '\n';
} else {
int all = st + sjh[0];
for (int i = 0; i < n; ++i)
cout << all - sjh[i] << ' ';
cout << '\n';
}
st += dt;
}
} else {
int fac = 1;
if (n > 12) fac = LLONG_MAX;
else {
for (int i = 1; i <= n; ++i)
fac = fac * i;
}
fac -= 3;
if (fac < k) cout << "NO\n";
else if (n % 2 == 1) {
cout << "YES\n";
vector<vector<int>> p; p.resize(3);
for (int i = 0; i < 3; ++i) p[i].resize(n);
fill(sjh, sjh + n, 0ll);
for (int i = 0; i < n; ++i) p[0][i] = i + 1, sjh[i] = i + 1;
int st = n / 2 + 1; for (int i = 0; i < n; ++i) {
p[1][i] = st; ++st; if (st > n) st = 1;
sjh[i] += p[1][i];
}
int all = n + sjh[0];
for (int i = 0; i < n; ++i) p[2][i] = all - sjh[i];
iota(p1 + 1, p1 + n + 1, 1ll);
iota(p2 + 1, p2 + n + 1, 1ll);
reverse(p2 + 1, p2 + n + 1);
k -= 3; k /= 2;
for (int i = 0; i < 3; ++i, cout << '\n')
for (int j = 0; j < n; ++j) cout << p[i][j] << ' ';
while (k--) {
int o[6] = {1, 1, 1, 1, 1, 1};
for (int i = 1; i <= n; ++i) if (p1[i] != p[0][i - 1]) o[0] = 0;
for (int i = 1; i <= n; ++i) if (p1[i] != p[1][i - 1]) o[1] = 0;
for (int i = 1; i <= n; ++i) if (p1[i] != p[2][i - 1]) o[2] = 0;
for (int i = 1; i <= n; ++i) if (p2[i] != p[0][i - 1]) o[3] = 0;
for (int i = 1; i <= n; ++i) if (p2[i] != p[1][i - 1]) o[4] = 0;
for (int i = 1; i <= n; ++i) if (p2[i] != p[2][i - 1]) o[5] = 0;
if (count(o, o + 6, 1ll) == 0) {
for (int i = 1; i <= n; ++i) cout << p1[i] << ' '; cout << '\n';
for (int i = 1; i <= n; ++i) cout << p2[i] << ' '; cout << '\n';
} else ++k;
next_permutation(p1 + 1, p1 + n + 1);
prev_permutation(p2 + 1, p2 + n + 1);
}
} else {
cout << "NO\n";
}
}
}
}
}
}
本文来自博客园,作者:yhbqwq,转载请注明原文链接:https://www.cnblogs.com/yhbqwq/p/18579270,谢谢QwQ
合集:
CodeForces 比赛合集
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 【.NET】调用本地 Deepseek 模型