聪明的打字员

1.前言

正解太妙了

2.题解

(1).暴力打法

6 6 6位上的数字压缩成一个 i n t int int,然后双向 b f s bfs bfs 爆搜即可,卡卡常数勉强过去

由于代码十分简单, 所以就不 打注释了

#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卡了过去,但是看到了 Z Z B ZZB ZZB巨佬和 14 14 14巨佬跑的快了不止 10 10 10倍,所以我去网上搜了正解。

网上的题解写的稀奇古怪,但我勉强弄明白了 T a Ta Ta所想表达的意思,照着 T a Ta Ta的思路顺利的解决了这道题。

我们可以预处理,得到一个三元组 (数列,光标位置,经过的原位置)

举个例子

原数列: 1 2 3 4 5 6 光标: 1

预处理数列:2 1 3 4 5 6 光标:2 所需步数:2 经过的位置:原1, 2

方案:
1.光标位置右移一位
2.交换 (1, 2)

然后我们在考虑用加减法

值会被改变的元素必定是被光标扫过的元素,所以我们可以在扫过的元素任意加减,加一次或减一次的价值是 1 1 1 (相当于是在扫到这个元素时就对它进行加减,使其符合最终位置)

思路理清了,代码就好写了

参考代码

#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.几句废话

由于作者水平有限和脑子刚弄丢了,所以讲解不清的地方请随意@

posted @ 2021-02-14 23:35  C2022lihan  阅读(39)  评论(0编辑  收藏  举报