首页 > 其他分享 >[CF1656G] Cycle Palindrome 的题解

[CF1656G] Cycle Palindrome 的题解

时间:2024-07-12 13:22:41浏览次数:12  
标签:cnt Palindrome int 题解 clear 交换 CF1656G 合并 include

题目大意

给定一个长度为 \(n\) 的数列 \(a\),要求求出一个排列 \(p\) 满足 \(a_{p_1},a_{p_2},\cdots ,a_{p_n}\) 是一个回文字符串而且把 \(i\) 向 \(p_i\) 连边得到的图中只有一个环。

数据范围满足,\(1\le \sum n\le 2\times10^5\)。

思路

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

  1. 如果 \(a_{p_i}=a_{p_j}\),那么 \(p_i\) 与 \(p_j\) 是可以交换的。
  2. 可以同时交换 \(p_i,p_j\) 和 \(p_{n-i+1},p_{n-j+1}\),这样原串的回文性质依旧满足。

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

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

交换 \(p_i,p_j\) 得到:

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

但是仅仅合并 \(a_{p_i}=a_{p_j}\) 的情况不可以合并所有的环,所以考虑将 \(p_i,p_j\) 和 \(p_{n-i+1},p_{n-j+1}\) 同时交换。

对于下图这种情况:


先交换 \(p_i,p_j\) 和 \(p_{n-i+1},p_{n-j+1}\),得到:

再交换 \(p_i\) 和 \(p_{n-i+1}\),因为 \(a\) 序列已经是一个回文串了,所以 \(a_{p_i}\) 与 \(a_{p_j}\) 注定是一样的。

因为通过第一种合并,我们将所有的 \(a_{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;
}

标签:cnt,Palindrome,int,题解,clear,交换,CF1656G,合并,include
From: https://www.cnblogs.com/liudagou/p/18298168

相关文章

  • [CF1646F] Playing Around the Table 的题解
    题目大意有\(n\)种牌,一种\(n\)张,一共\(n\)个玩家,一人\(n\)个。每个人一次将一张牌对给下家,求构造方案使可以在\(n\cdot(n-1)\)次操作之内使第\(i\)个人拥有\(n\)张\(i\)。数据范围满足,\(1\len\le100\)。思路因为直接构造出题目要求的情况会出现如果一个人提......
  • 2022 RoboCom CAIP(本科组)国赛个人题解
    RC-u1智能红绿灯为了最大化通行效率同时照顾老年人穿行马路,在某养老社区前,某科技公司设置了一个智能红绿灯。这个红绿灯是这样设计的:路的两旁设置了一个按钮,老年人希望通行马路时会按下按钮;在没有人按按钮的时候,红绿灯一直为绿灯;当红绿灯为绿灯时,有人按下按钮,第一次按下......
  • CF1992场题解
    OnlyPluses算法:数学。题意简述:有三个数,每次选择一个数\(x\),使得\(x\)增加一,至多操作\(5\)次,最后求出这三个数的乘积最大值。简单题,一眼秒了。考虑把这\(3\)个数从小到大排序,显然加最小的数比加其他的数更优。简单证一下:设排序后的三个数为\(a,b,c\),有\(b\timesc\ge......
  • upload-labs靶场全题解
    ​​靶场搭建对php和apache版本有严格要求,建议使用phpstudy2018并且使用设置php版本为5.2.17,这个靶场比较老了,如果要复现的话,必要严格按照要求来使用,博主使用最新版的phpstudy在某些靶场上未能成功复现,所以浪费了很多时间。。。。。Upload-Labs环境要求操作系统:wind......
  • 2024SCAU暑假集训_1题解(部分,待补充)
    最近我们开始了暑假集训现在我来补一下第一场集训的题解题目题号来源是否写了题解A黑暗爆炸4771否但是放了大佬的链接指路B黑暗爆炸3399已写C洛谷P3231D洛谷P2120ECodeForces197AF洛谷P1732GBZOJ5296H黑暗爆炸1406......
  • 多线程中自定义线程池与shiro导致的权限错乱问题解决
    importorg.apache.shiro.SecurityUtils;importorg.apache.shiro.subject.Subject;importorg.apache.shiro.util.ThreadContext;importjava.util.concurrent.*;publicclassShiroAwareThreadPoolExecutorextendsThreadPoolExecutor{publicShiroAwareThread......
  • Linux创建组和用户groupadd:无法锁定/etc/group问题解决
    问题原因:相关关键文件进行了锁定,不能被访问和修改1.确认是否是使用root用户执行,2.确定文件权限没问题使用lsattr命令查看隐藏权限设定情况[abc@localhost~]$lsattr/etc/group----------------/etc/group[abc@localhost~]$lsattr/etc/passwd----------------/etc/......
  • Codeforces Round #956 (Div. 2)题解
    A.ArrayDivisibility需要让满足$k\midj$的所有\(a_j\)的和整除k,只需要让每个\(a_j\)整除k就可以了,可以让\(a_j=j\)#include<bits/stdc++.h>usingnamespacestd;#defineintlonglong#defineendl'\n'typedefpair<int,int>pii;typedefunsignedlonglo......
  • CF1051F题解
    TheShortestStatement算法:树链剖分,最小生成树,最短路。先讲一下题意:有一个\(n\)点\(m\)边的无向连通图,\(q\)次询问,每次询问\(a\)到\(b\)的最短路长度。数据范围\(1\len,m\le10^5,m-n\le20\)。首先发现给了一个很奇怪的限制:\(m-n\le20\),考虑他有什么用。我们在......
  • 【完结】LeetCode 热题 HOT 100分类+题解+代码详尽指南
    目录LeetCode热题100前言LeetcodeTop100题目和答案-哈希LeetcodeTop100题目和答案-双指针篇LeetcodeTop100题目和答案-滑动窗口篇LeetcodeTop100题目和答案-子串篇LeetcodeTop100题目和答案-普通数组篇LeetcodeTop100题目和答案-矩阵篇LeetcodeTop100题目和......