题目大意

给定一个长度为 nn 的数列 aa,要求求出一个排列 pp 满足 ap1,ap2,,apna_{p_1},a_{p_2},\cdots ,a_{p_n} 是一个回文字符串而且把 iipip_i 连边得到的图中只有一个环。

数据范围满足,1n2×1051\le \sum n\le 2\times10^5

思路

先不考虑 pp 是否构成满足要求的环,这样这个题目就很简单了。在构造出了满足 ap1,ap2,,apna_{p_1},a_{p_2},\cdots ,a_{p_n} 是回文串的 pp 数组之后,考虑哪些 pp 中的位置是可以交换的。

  1. 如果 api=apja_{p_i}=a_{p_j},那么 pip_ipjp_j 是可以交换的。
  2. 可以同时交换 pi,pjp_i,p_jpni+1,pnj+1p_{n-i+1},p_{n-j+1},这样原串的回文性质依旧满足。

在连出的图中,考虑怎么将多个环通过合法的交换合并。

对于下面的这种情况,我们可以在 api=apja_{p_i}=a_{p_j} 的情况下交换 pi,pjp_i,p_j 将两个环合并。

交换 pi,pjp_i,p_j 得到:

可以看到这样这两个环就合并了。

但是仅仅合并 api=apja_{p_i}=a_{p_j} 的情况不可以合并所有的环,所以考虑将 pi,pjp_i,p_jpni+1,pnj+1p_{n-i+1},p_{n-j+1} 同时交换。

对于下图这种情况:


先交换 pi,pjp_i,p_jpni+1,pnj+1p_{n-i+1},p_{n-j+1},得到:

再交换 pip_ipni+1p_{n-i+1},因为 aa 序列已经是一个回文串了,所以 apia_{p_i}apni+1a_{p_{n-i+1}} 注定是一样的。

因为通过第一种合并,我们将所有的 apia_{p_i} 的值一样的点全部都到了一个环里,所以在第二个操作中注定可以将能合并的全部合并。

对于具体的实现,考虑使用并查集维护一下是否在一个环中,接着模拟即可。

#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
using namespace std;
const int N=2e5+5;
int n,p[N];
struct node{int x,p,id;}a[N];
bool cmp(node a,node b){return a.x<b.x;}bool cmp1(node a,node b){return a.id<b.id;}
map<int,int>mp;
struct CJH{
    int fa[N];void clear(){for(int i=1;i<=n;i++)fa[i]=i;}
    int find_root(int x){return fa[x]==x?x:fa[x]=find_root(fa[x]);}
    int ask(int x,int y){return find_root(x)==find_root(y);}
    void add(int x,int y){fa[find_root(x)]=find_root(y);}
}dsu;
vector<int> v[N];
void solve(){
    cin>>n;
    dsu.clear(),mp.clear();
    for(int i=1;i<=n;i++){
        cin>>a[i].x,a[i].id=i;
        mp[a[i].x]++,v[i].clear();
    }
    int cnt=0;
    for(auto i:mp) if(i.second&1) cnt++;
    if(cnt>1||cnt==1&&n%2==0){cout<<"NO\n";return;}
    int tot=0;
    sort(a+1,a+1+n,cmp);
    for(int i=1;i<=n;i++){
        if(i<n&&a[i].x==a[i+1].x) p[++tot]=a[i].id,p[n-tot+1]=a[++i].id;
        else p[(n+1)/2]=a[i].id;
    }
    sort(a+1,a+1+n,cmp1);
	for(int k=1;k<=n;k++) a[k].p=p[k];
    mp.clear(),tot=0;
    for(int i=1;i<=n;i++) if(!mp[a[i].x]) mp[a[i].x]=++tot;
    for(int i=1;i<=n;i++){
        dsu.add(i,a[i].p);
        v[mp[a[a[i].p].x]].push_back(i);
    }
    for(int i=1;i<=tot;i++){
        for(int j=1;j<v[i].size();j++){
            if(!dsu.ask(v[i][0],v[i][j])){
                swap(a[v[i][0]].p,a[v[i][j]].p);
                dsu.add(v[i][0],v[i][j]);
            }
        }
    }
    for(int i=2;i<n-i+1;i++){
        if(!dsu.ask(1,i)){
            dsu.add(1,i);
            swap(a[1].p,a[i].p);
            swap(a[n].p,a[n+1-i].p);
            swap(a[1].p,a[n].p);
        }
    }
    for(int i=2;i<=n;i++){if(!dsu.ask(1,i)){cout<<"NO\n";return;}}
    cout<<"YES\n";for(int i=1;i<=n;i++) cout<<a[i].p<<' ';cout<<'\n';
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T;cin>>T;
    while(T--) solve();
    return 0;
}