1.前言
正解太妙了
2.题解
(1).暴力打法
将666位上的数字压缩成一个intintint,然后双向 bfsbfsbfs 爆搜即可,卡卡常数勉强过去
由于代码十分简单, 所以就不 想 打注释了
#include <queue>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define Get(x, y) (x / w[y] % 10)
#define LL long long
#define ULL unsigned long long
template <typename T> void read (T &x) {x = 0; T f = 1;char tem = getchar ();while (tem < '0' || tem > '9') {if (tem == '-') f = -1;tem = getchar ();}while (tem >= '0' && tem <= '9') {x = (x << 1) + (x << 3) + tem ;tem = getchar ();}x *= f;}
template <typename T> void write (T x) {if (x < 0) {x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> T Max (T x, T y) { return x > y ? x : y; }
template <typename T> T Min (T x, T y) { return x < y ? x : y; }
template <typename T> T Abs (T x) { return x > 0 ? x : -x; }
const int Maxn = 6;
const int Maxkind = 5999999;
int n = 6;
int w[Maxn + 1] = {1, 10, 100, 1000, 10000, 100000, 1000000};
char s_str[Maxn], t_str[Maxn];
struct Node {
int step, Index, val;
bool flag;
}s, t;
int hh = 1, tt = 0;
queue <Node> q;
int vis[2][Maxkind + 5];
int Get_Order (char c[], int Index) {
int res = Index;
for (int i = 0; i < n; i++)
res = res * 10 + c[i] - '0';
return res;
}
int Two_Way_bfs () {
memset (vis, -1, sizeof vis);
s.step = t.step = 0; s.flag = 1; t.flag = 0; s.Index = n - 1; s.val = Get_Order (s_str, s.Index);
q.push (s); vis[s.flag][s.val] = 0;
for (int i = 0; i < n; i++) {
t.Index = i; t.val = Get_Order (t_str, i);
q.push (t);
vis[t.flag][t.val] = 0;
}
while (q.size ()) {
Node Now = q.front (); q.pop ();
++Now.step;
if (Now.Index != 0) {
int last = Now.val;
Now.val = Now.val + Get (Now.val, Now.Index) - Get (Now.val, Now.Index) * w[Now.Index] + (Now.val % 10) * w[Now.Index] - Now.val % 10;
if (vis[Now.flag ^ 1][Now.val] != -1)
return Now.step + vis[Now.flag ^ 1][Now.val];
if (vis[Now.flag][Now.val] == -1) {
vis[Now.flag][Now.val] = Now.step;
q.push (Now);
}
Now.val = last;
}
if (Now.Index != n - 1) {
int last = Now.val;
Now.val = Now.val + Get (Now.val, Now.Index) * w[n - 1] - Get (Now.val, Now.Index) * w[Now.Index] + Get (Now.val, n - 1) * w[Now.Index] - Get (Now.val, n - 1) * w[n - 1];
if (vis[Now.flag ^ 1][Now.val] != -1)
return Now.step + vis[Now.flag ^ 1][Now.val];
if (vis[Now.flag][Now.val] == -1) {
vis[Now.flag][Now.val] = Now.step;
q.push (Now);
}
Now.val = last;
}
if (Get (Now.val, Now.Index) != 0) {
int last = Now.val;
Now.val -= w[Now.Index];
if (vis[Now.flag ^ 1][Now.val] != -1)
return Now.step + vis[Now.flag ^ 1][Now.val];
if (vis[Now.flag][Now.val] == -1) {
vis[Now.flag][Now.val] = Now.step;
q.push (Now);
}
Now.val = last;
}
if (Get (Now.val, Now.Index) != 9) {
int last = Now.val;
Now.val += w[Now.Index];
if (vis[Now.flag ^ 1][Now.val] != -1)
return Now.step + vis[Now.flag ^ 1][Now.val];
if (vis[Now.flag][Now.val] == -1) {
vis[Now.flag][Now.val] = Now.step;
q.push (Now);
}
Now.val = last;
}
if (Now.Index != 0) {
int last = Now.val;
Now.Index--;
Now.val -= w[n];
if (vis[Now.flag ^ 1][Now.val] != -1)
return Now.step + vis[Now.flag ^ 1][Now.val];
if (vis[Now.flag][Now.val] == -1) {
vis[Now.flag][Now.val] = Now.step;
q.push (Now);
}
Now.Index++;
Now.val = last;
}
if (Now.Index != n - 1) {
int last = Now.val;
Now.Index++;
Now.val += w[n];
if (vis[Now.flag ^ 1][Now.val] != -1)
return Now.step + vis[Now.flag ^ 1][Now.val];
if (vis[Now.flag][Now.val] == -1) {
vis[Now.flag][Now.val] = Now.step;
q.push (Now);
}
Now.Index--;
Now.val = last;
}
}
return -1;
}
int main () {
scanf ("%s %s", s_str, t_str);
bool flag = 1;
for (int i = 0; i < n; i++) {
if (s_str[i] != t_str[i])
flag = 0;
}
if (flag) {
printf ("0");
return 0;
}
cout << Two_Way_bfs ();
return 0;
}
(2).神奇的正解
虽然我用法1卡了过去,但是看到了 ZZBZZBZZB巨佬和141414巨佬跑的快了不止101010倍,所以我去网上搜了正解。
网上的题解写的稀奇古怪,但我勉强弄明白了TaTaTa所想表达的意思,照着TaTaTa的思路顺利的解决了这道题。
我们可以预处理,得到一个三元组 (数列,光标位置,经过的原位置)
举个例子
原数列: 1 2 3 4 5 6 光标: 1
预处理数列:2 1 3 4 5 6 光标:2 所需步数:2 经过的位置:原1, 2
方案:
1.光标位置右移一位
2.交换 (1, 2)
然后我们在考虑用加减法
值会被改变的元素必定是被光标扫过的元素,所以我们可以在扫过的元素任意加减,加一次或减一次的价值是111 (相当于是在扫到这个元素时就对它进行加减,使其符合最终位置)
思路理清了,代码就好写了
参考代码
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define ULL unsigned long long
#define Move(x) (1 << x - 1)
#define Get(x, y) ((x >> y - 1) & 1)
using namespace std;
template <typename T> int read (T &x) {x = 0; T f = 1;char tem = getchar ();while (tem < '0' || tem > '9') {if (tem == '-') f = -1;tem = getchar ();}while (tem >= '0' && tem <= '9') {x = (x << 1) + (x << 3) + tem - '0';tem = getchar ();}x *= f; return 1;}
template <typename T> void write (T x) {if (x < 0) {x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> T Max (T x, T y) { return x > y ? x : y; }
template <typename T> T Min (T x, T y) { return x < y ? x : y; }
template <typename T> T Abs (T x) { return x > 0 ? x : -x; }
const int Maxn = 6;
const int Maxkind = 5040;
const int Inf = 0x3f3f3f3f;
int n = 6;
int ans[Maxkind * 10 + 6 + 5];
int vis[Maxkind * 10 + 6 * 5];
struct node {
int Index, c[Maxn + 5];
int vis;
//Index记录光标最后的位置
//c[i]记录i号位置的元素原来的下标
//vis记录了那些元素被扫过(状态压缩)
};
int fac[Maxn + 5] = {1, 1, 2, 6, 24, 120, 720, 5040};
struct Cantor {//康拓展开模板
int n, order;
int c[Maxn + 5], BIT[Maxn + 5], Bit[Maxn + 5];
Cantor () { memset (Bit, 0, sizeof Bit); memset (BIT, 0, sizeof BIT); }
int lowbit (int x) { return x & -x; }
void Update (int Index, int x, int *str) {
for (int i = Index; i < Maxn + 5; i += lowbit (i))
str[i] += x;
}
int Sum (int x, int *str) {
int res = 0;
for (int i = x; i >= 1; i -= lowbit (i))
res += str[i];
return res;
}
int Get_order () {
int sum = 0;
for (int i = n; i >= 1; i--) {
sum += Sum (c[i], BIT) * fac[n - i];
Update (c[i], 1, BIT);
}
order = sum;
return sum;
}
void Get_Seq () {
int tem = order;
for (int i = 1; i <= n; i++) Update (i, 1, Bit);
for (int i = 1; i <= n; i++) {
int l = 1, r = n, x = tem / fac[n - i] + 1;
tem %= fac[n - i];
while (l + 1 < r) {
int mid = l + r >> 1;
if (Sum (mid, Bit) < x)
l = mid;
else
r = mid;
}
if (Sum (l, Bit) == x) c[i] = l;
else c[i] = r;
Update (c[i], -1, Bit);
}
}
};
int Get_Order (node x) {//记录路径
int res = 0;
for (int i = n; i >= 1; i--) {
int cnt = 0;
for (int j = i + 1; j <= n; j++) {
if (x.c[j] < x.c[i]) {
cnt++;
}
}
res += fac[n - i] * cnt;
}
int val = res * 10 + x.Index;
return val;
}
void Bfs () {//预处理
node Start; Start.Index = 1; Start.vis = 0;
queue <node> q;
for (int i = 1; i <= n; i++)
Start.c[i] = i;//Start.c记录元素下标
Start.vis |= 1;
q.push (Start);
memset (ans, -1, sizeof ans);
ans[Get_Order (Start)] = 0; vis[Get_Order (Start)] = Start.vis;
while (q.size ()) {
node Now = q.front (), Next; q.pop ();
int Val_Now = Get_Order (Now);
if (Now.Index != 1) {//光标左移
Next = Now; Next.Index--; Next.vis |= Move (Next.Index);
int Val_Next = Get_Order (Next);
if (ans[Val_Next] == -1) {
ans[Val_Next] = ans[Val_Now] + 1;
vis[Val_Next] = Next.vis;
q.push (Next);
}
}
if (Now.Index != 1) {//swap (1, Index)
Next = Now; swap (Next.c[1], Next.c[Next.Index]);
int Val_Next = Get_Order (Next);
if (ans[Val_Next] == -1) {
ans[Val_Next] = ans[Val_Now] + 1;
vis[Val_Next] = Next.vis;
q.push (Next);
}
}
if (Now.Index != n) {//光标右移
Next = Now; Next.Index++; Next.vis |= Move (Next.Index);
int Val_Next = Get_Order (Next);
if (ans[Val_Next] == -1) {
ans[Val_Next] = ans[Val_Now] + 1;
vis[Val_Next] = Next.vis;
q.push (Next);
}
}
if (Now.Index != n) {//swap (Index, n)
Next = Now; swap (Next.c[n], Next.c[Next.Index]); Next.vis |= Move (n);
int Val_Next = Get_Order (Next);
if (ans[Val_Next] == -1) {
ans[Val_Next] = ans[Val_Now] + 1;
vis[Val_Next] = Next.vis;
q.push (Next);
}
}
}
}
char s[Maxn + 5], t[Maxn + 5];
int main () {
Bfs ();//预处理
scanf ("%s %s", s + 1, t + 1);
int cnt = Inf;
for (int i = 0; i < fac[n]; i++) {//枚举状态
Cantor Now;
Now.n = n; Now.order = i; Now.Get_Seq ();
for (int j = 1; j <= n; j++) {//指针最后停在j
int res = ans[i * 10 + j];
for (int k = 1; k <= n; k++) {//判断每一位需要的价值
//目前k号位的元素的下标是Now.c[k]
if (s[Now.c[k]] != t[k] && Get (vis[i * 10 + j], Now.c[k]) == 0) {
//如果相对的元素值不相符且无法修改
res = Inf;
//不能选择此方案
}
res += Abs (s[Now.c[k]] - t[k]);
//将相对的元素值修改
}
cnt = Min (cnt, res);//去最小值
}
}
printf ("%d", cnt);
return 0;
}
3.几句废话
由于作者水平有限和脑子刚弄丢了,所以讲解不清的地方请随意@