Codeforces.612E.Square Root of Permutation(构造)

本文探讨了一个有趣的排列问题,给定一个n的排列p_i,目标是找到另一个排列q_i,使得q_{q_i}

题目链接


\(Description\)

给定一个\(n\)的排列\(p_i\),求一个排列\(q_i\),使得对于任意\(1\leq i\leq n\)\(q_{q_i}=p_i\)。无解输出\(-1\)
\(1\leq n\leq10^6\)

\(Solution\)

对排列\(q_i\)我们建一张图,边为\(i\to q_i\)。显然这张图是由几个环构成。
发现对于\(q_{q_i}\)的图,原来\(q_i\)中的奇环它们还是类似的一个奇环,原来的偶环会分裂成两个大小相等的偶环。
所以对\(p_i\)建图,找出里面的环,是奇环就把相邻点间隔为\(2\)地插入到环里,是偶环就找到和它一样大的一个合并,找不到就无解。这样就可以得到\(q_i\)的图了。(每个偶环只能合并一次→_→)
复杂度\(O(n)\)


//249ms 21300KB
#include <cstdio>
#include <cctype>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 1000000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=1e6+5;

int nxt[N],q[N],tmp[N],tmp2[N],id[N];
bool vis[N];
char IN[MAXIN],*SS=IN,*TT=IN;

inline int read()
{
    int now=0;register char c=gc();
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);now=now*10+c-48,c=gc());
    return now;
}

int main()
{
    const int n=read();
    for(int i=1; i<=n; ++i) nxt[i]=read();
    for(int s=1; s<=n; ++s)
        if(!vis[s])
        {
            int cnt=0,x=s;
            do
            {
                tmp[++cnt]=x, vis[x]=1, x=nxt[x];
            }while(x!=s);
            if(cnt&1)
            {
                for(int i=1,now=0; i<=cnt; ++i,(now+=2)>=cnt&&(now-=cnt)) tmp2[now]=tmp[i];
                for(int i=0; i<cnt; ++i) q[tmp2[i]]=tmp2[i+1];
                q[tmp2[cnt-1]]=tmp2[0];
            }
            else
            {
                if(!id[cnt]) id[cnt]=s;
                else
                {
                    int y=id[cnt],x=y,t=0;
                    do
                    {
                        tmp2[++t]=x, x=nxt[x];
                    }while(x!=y);
                    for(int t1=1,t2=1,las=tmp[1],i=t<<1; i; --i)
                        las=q[las]=i&1?tmp[++t1]:tmp2[t2++];
                    q[tmp2[t]]=tmp[1], id[t]=0;
                }
            }
        }
    for(int i=2; i<=n; i+=2) if(id[i]) return puts("-1"),0;
    for(int i=1; i<=n; ++i) printf("%d ",q[i]);

    return 0;
}

转载于:https://www.cnblogs.com/SovietPower/p/10528010.html

《完整神武新章服务端源码》是一个与游戏开发相关的资源,主要使用Delphi编程语言编写的。 Delphi是一款强大的面向对象的集成开发环境(IDE),尤其在Windows平台上的应用开发方面享有很高的声誉。 本资源包含的服务端源码是网络游戏《神武新章》的核心部分,它负责处理游戏服务器的逻辑、网络通信、数据库交互以及玩家间的游戏行为同步等关键功能。 1. **Delphi编程基础**:Delphi采用Object Pascal语言,它是一种高效且简洁的面向对象语言。 源码中可能包含类定义、继承、多态性、接口等面向对象设计概念。 理解Delphi的基本语法和面向对象特性是分析和修改源码的基础。 2. **网络编程**:服务端源码中必然涉及网络通信模块,如TCP/IP协议栈的使用,用于建立客户端和服务端之间的连接。 源码地址: https://pan.quark.cn/s/4014bf1007ee 这部分可能涉及到套接字编程,包括监听、接受连接、发送和接收数据等操作。 3. **并发处理**:由于服务器需要同时处理多个客户端的请求,因此并发处理是服务端源码中的重要部分。 Delphi提供了线程和异步编程机制,如TThread类和IO完成端口等技术,用于实现高效的并发控制。 4. **数据库交互**:游戏服务端通常需要与数据库进行交互,存储和检索玩家信息、游戏数据等。 可能使用到ADO(ActiveX Data Objects)或DirectSQL等数据库访问组件,掌握SQL语言和数据库事务处理是必要的。 5. **游戏逻辑**:这部分源码包含了游戏规则的实现,比如角色移动、战斗计算、任务系统等。 这些逻辑可能分布在多个类和函数中,通过事件驱动或消息传递机制进行协调。 6. **加密与安全**:...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值