THUSC2022 D. 造计算机

又被构造杀了。。。

不同轮换的交换位置不会重复,

一个自然的思路是把所有轮换提出来,按长度的奇偶考虑

1.偶环

这种时候可以通过 2 个寄存器解决。

可以将环上的 1,2 号元素放入 1,2 号寄存器

然后将 1 放在 2 的位置,将 3 放入寄存器 1 ,以此类推

2.奇环

m=3 的构造:

注意到与偶环不同的情况在于最后一个元素没办法换到寄存器上

那么我们再用一个寄存器放最后一个元素即可

m=2 的构造:

将第 n 个元素通过寄存器 2 换到 1 , 注意此时寄存器 2 内的元素为 2 ,再把第 2 个元素换到寄存器 1

然后将寄存器 2 的元素放在 2 , 将元素 3 放在寄存器 2 ,以此类推。

最后一步时第 n 个位置是空的,并且元素在寄存器 1 中,直接换就可以了。

最后将 m 个寄存器内部排序即可

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair< int , int >
#define fi first
#define sc second
#define mp make_pair

const int MAXN = 2e5;
int n , m , a[ MAXN + 5 ];
vector< pii > op; vector< int > pos;
queue< int > q; //map< pii , bool > use;

void opt( int u , int v ) {
    // assert( !use[ mp( u , v ) ] );
    op.push_back( mp( u , v ) );
    swap( a[ u ] , a[ v ] ); 
    // use[ mp( u , v ) ] = use[ mp( v,  u ) ] = 1;
}
int main( ) {
    scanf("%d",&n);
    for( int i = 1 ; i <= n ; i ++ ) scanf("%d",&a[ i ]);
    for( int i = n + 1 ; i <= 2 * n ; i ++ ) a[ i ] = i;
    
    int m = 1;
    for( int i = 1 ; i <= n ; i ++ ) if( i != a[ i ] ) {
        int cnt = 1;
        pos.clear(); pos.push_back( i );
        for( int j = a[ i ] ; j != i ; j = a[ j ] ) cnt ++ , pos.push_back( j );

        if( cnt % 2 == 0 ) {
            m = max( m , 2 );
            opt( pos[ 0 ] , n + 1 ); opt( pos[ 1 ] , n + 2 );
            for( int j = 1 ; j < cnt - 1 ; j ++ ) {
                opt( n + 1 + !( j & 1 ) , pos[ j ] );
                opt( pos[ j + 1 ] , n + 1 + !( j & 1 ) );
            }
            opt( n + 1 , pos[ cnt - 1 ] ); opt( n + 2 , pos[ 0 ] );
        }
        if( cnt & 1 ) {
            m = max( m , 2 );
            opt( pos[ cnt - 1 ] , n + 2 ); opt( n + 2 , pos[ 0 ] );
            opt( pos[ 1 ] , n + 1 );
            for( int j = 1 ; j < cnt - 1 ; j ++ ) {
                opt( n + 1 + ( j & 1 ) , pos[ j ] );
                if( j != cnt - 2 ) opt( pos[ j + 1 ] , n + 1 + ( j & 1 ) );
            }
            opt( n + 1 , pos[ cnt - 1 ] );
        }
    }
    if( m == 1 ) return printf("0 0\n") & 0;
    
    for( int i = n + 1 ; i <= 2 * n ; i ++ ) if( a[ i ] != i ) q.push( i );
    while( !q.empty() ) {
        int u = q.front(); q.pop();
        if( u == a[ u ] ) continue;
        opt( u , a[ u ] ); if( u != a[ u ] ) q.push( u );
    }

    // for( int i = 1 ; i <= n + m ; i ++ ) printf("%d ", a[ i ] ); puts("");

    printf("%d %d\n", m , op.size() );
    for( pii v : op ) printf("%d %d\n", v.fi , v.sc );
    return 0;
}
posted @   chihik  阅读(122)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示