[CF936C] Lock Puzzle
前言
终于自己做出来一道构造题了!
题目
讲解
\(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;
}