[CF936C] Lock Puzzle

前言

终于自己做出来一道构造题了!

题目

CF

洛谷

讲解

\(n\le2000\),限制\(6100\),我们不难猜测有一个\(3n\)的做法

猜测是一个字母一个字母地使其有序,每个字母有\(3\)次机会到指定位置

通过一顿乱搞,发现如下方法:

图中蓝色箭头为之前已经排好的有序的字母(目标串的前缀),黑点为我们要放到蓝色箭头右边的字母

其余颜色的箭头为其它无序字母

箭头的方向代表了是否反转

建议结合代码食用

判断无解就是判断是否字母数不同

代码

大常数代码

const int MAXN = 2005;
int n;
char s[MAXN],t[MAXN],tmp[MAXN]; 
int cnt[256];
int ans[MAXN * 3],anstot;

bool check()
{
	for(int i = 1;i <= n;++ i) if(s[i] != t[i]) return 0;
	return 1;
}
void Add(int x) 
{
	if(!x) return;
	ans[++anstot] = x;
	for(int i = n-x+1;i <= n;++ i) tmp[n-i+1] = s[i];
	for(int i = 1;i <= n-x;++ i) tmp[i+x] = s[i];
	for(int i = 1;i <= n;++ i) s[i] = tmp[i];
}

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	n = Read();
	scanf("%s%s",s+1,t+1);
	for(int i = 1;i <= n;++ i) cnt[s[i]]++;
	for(int i = 1;i <= n;++ i)
	{
		cnt[t[i]]--;
		if(cnt[t[i]] < 0)
		{
			printf("-1");
			return 0;
		}
	}
	for(int i = 1;i <= n;++ i)
	{
		if(check()) break;//删了更快的剪枝
		int ID = 0;
		for(int j = 1;!ID;++ j)
			if(s[j] == t[i])
				ID = j;
		//寻找“黑点”
		Add(n-ID);
		Add(1);
		Add(n);
		//使用三次转换机会
	}
	Put(anstot,'\n');
	for(int i = 1;i <= anstot;++ i) Put(ans[i],' ');
	return 0;
}
posted @ 2020-12-22 22:16  皮皮刘  阅读(94)  评论(0编辑  收藏  举报