移方块 Shift 题解
2026-08-14 21:05:23
发布于:湖北
5阅读
0回复
0点赞
这道题只要知道是采用归位法,从小到大将元素依次放到正确位置就可以解出来了。
注意事项:
操作次数需对 n(对于 a) 或 (对于 b) 取模,因为超过周期会还原。
输出时确保相邻块类型不同,且每块的次数满足 。
Code:
#include <bits/stdc++.h>
using namespace std;
const int N = 2e3 + 5, M = 4e6 + 5;
int n, ps = 1, tp, a[N], a1[N], a2[N];
struct Answer {
int op, x; // op: 0 for a, 1 for b
} ans[M];
// 执行 x 次 a 操作(循环右移 x 位),并记录块
void f(int x) {
ps = (ps - x % n + n - 1) % n + 1; // 更新起始指针
if (!tp || ans[tp].op) // 若当前没有块或块类型为 b,则新建一个 a 块
ans[++tp] = {0, 0};
ans[tp].x = (ans[tp].x + x) % n; // 次数合并,模 n(因为次数 < n)
if (!ans[tp].x) --tp; // 次数为 0 则删除块
}
// 执行一次 b 操作(等价于前三个元素循环右移),并记录块
void f1() {
swap(a[ps % n + 1], a[(ps + 1) % n + 1]);
swap(a[ps], a[ps % n + 1]);
if (!tp || !ans[tp].op) // 若当前无块或块类型为 a,则新建一个 b 块
ans[++tp] = {1, 0};
ans[tp].x = (ans[tp].x + 1) % 3; // b 操作次数模 3
if (!ans[tp].x) --tp;
}
// 执行两次 b 操作(等价于前三个元素循环左移),记录为 b 块
void f2() {
swap(a[ps], a[ps % n + 1]);
swap(a[ps % n + 1], a[(ps + 1) % n + 1]);
if (!tp || !ans[tp].op)
ans[++tp] = {1, 0};
ans[tp].x = (ans[tp].x + 2) % 3;
if (!ans[tp].x) --tp;
}
void fail() { printf("NIE DA SIE\n"); }
void print() {
printf("%d\n", tp);
for (int i = 1; i <= tp; ++i)
printf("%d%c ", ans[i].x, ans[i].op + 'a');
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
if (n == 1) {
printf("0\n");
return 0;
}
if (n == 2) {
if (a[1] == 1) printf("0\n");
else printf("1\n1a\n");
return 0;
}
// 将 1..n-2 归位
for (int i = 1, t = 0; i <= n - 2; ++i) {
// 找到 i 的位置
for (int j = 1; j <= n; ++j)
if (a[j] == i) { t = j; break; }
// 通过 a 操作将 i 移到序列开头
f(n - t + 1);
// 第一个元素特殊处理
if (i == 1) {
// 将已排好的前缀循环左移,更新 ps
// clr() 函数将当前序列从 ps 处断开,使 ps=1
// 实际上 clr() 将 a 重新构造为从 ps 开始的新序列
clr();
continue;
}
// 将 i 从开头移动到第 i 个位置
t -= 2;
while (t > 0) {
if (t > 1) {
f(2); // 右移 2 位
f1(); // 一次 b
t -= 2;
} else {
f(1); // 右移 1 位
f2(); // 两次 b
--t;
}
}
clr(); // 更新 ps
}
// 最后处理 n-1, n
f(n - 3);
clr();
if (a[n] == n) {
print();
return 0;
}
if (n & 1) {
fail();
return 0;
}
// n 为偶数,交换最后两个元素
f(1);
for (int i = 1; i < n / 2; ++i)
f2(), f(n - 2);
f(n - 2);
clr();
print();
return 0;
}
这里空空如也







有帮助,赞一个