- 给定 $n$ 和数字串 $a_1,a_2,\cdots,a_n$,$b_1,b_2,\cdots,b_n$。
- 定义一次操作为:将一个等长且不相交的前缀和后缀对应位置交换。举例:${1,2,3,4,5,6}$ 交换长度为 $2$ 的前后缀变为 ${5,6,3,4,1,2}$。
- 可以对 $a$ 进行任意次操作,问是否能变成 $b$。多组数据。
- $1\leq T\leq 500,1\leq n\leq 500,1\leq a_i,b_i\leq 10^9$。
sol
- 一个显然的结论:如果 $n$ 为奇数,则两个串 $\frac {n+1}2$ 位置必须相同(因为不能翻转)。
- 我们称下标和为 $n+1$ 的数是对应的(换句话说,第 $i$ 个位置的数和第 $n-i+1$ 位置的数是对应的),那么可以发现,对应位置形成的无序对是永远不会改变的(对于左边的数 $i$ 移动到 $i+(n-k)$,对于右边的数 $n-i+1$ 移动到 $n-i+1-(n-k)$,它们之和依旧为 $n+1$)。
- 于是大胆猜测原问题等价于是否满足 $a,b$ 无序对相同。
证明
- 首先,上述结论是必要的。
- 其次,若对于满足上述结论的 $a$,能构造出合法的操作序列,那么原问题和 $a$ 是否满足上述结论是等价的。接下来需要构造操作序列。
- 朴素的想法是从中间到两边依次确定,因为固定住中间不影响后续操作,且固定后不影响上述结论是否成立(删除了相同的无序对不影响结论)。
- 考虑现在固定 $a_i,a_{n-i+1}$,找相同的无序对 $a_j,a_{n-j+1}$ 移动过来。设 $a_i=a_j$,分情况讨论:
- $j=n$,那么直接翻转长度为 $i$ 的前后缀,那么 $a_n$ 翻到 $a_i$,$a_1$ 翻到 $a_{n-i+1}$,满足条件;
- $j=1$,那么直接翻转长度为 $1$ 的前后缀,就变成 1. 的情况了;
- 其它,那么翻转长度为 $j(n-j+1)$ 的前后缀,那么 $j$ 就变成 1./2. 的情况了。
- 这样就变成规模更小的子问题了,所以证明了满足上述条件即成立。
```cpp
include
using namespace std;
typedef pair
int T,n,a[510],b[510];
pii x[510],y[510];
bool check(){
int m=(n>>1)+1;
if ((n&1)&&a[m]!=b[m]) return false;
for (int i=1;i<m;i++){
x[i]=pii(min(a[i],a[n-i+1]),max(a[i],a[n-i+1]));
y[i]=pii(min(b[i],b[n-i+1]),max(b[i],b[n-i+1]));
}
sort(x+1,x+m); sort(y+1,y+m);
for (int i=1;i<m;i++)
if (x[i]!=y[i]) return false;
return true;
}
int main(){
scanf("%d",&T);
while (T--){
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<=n;i++) scanf("%d",&b[i]);
if (check()) puts("Yes");
else puts("No");
}
return 0;
}
```