zoukankan      html  css  js  c++  java
  • Valera and Swaps

    题意:

    定义 $f(p)$ 表示将 $p$ 序列变换为有序序列最少要交换多少次,给一 $1 sim n$ 的排列 $a$ ,给一整数 $m$,

    求问将 $a$ 最少交换多少次能得到 $p$ ,使得 $f(p) = m$,并将以此交换视作一个两个数字,将交换按顺序排列开

    求出字典序最小的交换序列。

    解法:

    记 $id$ 表示排列 $id(i) = i$

    考虑 $f(p)$ 怎么求,可以发现,将原排列视作一个从$p$置换到$id$的置换,则将置换拆分成 $tot$ 个循环后,

    最小交换次数就是$sum_{i=1}^{tot}{cnt_i - 1}$,也就是$n - tot$。

    这样考虑交换两个置换的元素,两个置换群会合为一个置换群, $tot$ 变为 $tot-1$。

    考虑交换一个置换群内的元素,当前置换群会拆分为两个置换群,$tot$ 变为 $tot+1$。

    我们注意到要求交换次数最小,这样两种操作一定不会共存,

    这样分类讨论:

    1.$n-m < tot$时,我们需要将原先的置换群不断合并,要求字典序最小,

    所以我们每次找出含最小元素的置换,将其与含1的置换合并。

    2.$n-m = tot$时,不用交换,答案为0

    3.$n-m > tot$时,每一次我们只要选择含最小元素的置换,将其中的最小值和次小值交换,并将置换拆开。

    总复杂度$O(n^2)$

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <vector>
     5 
     6 #define N 3010
     7 #define LL long long
     8 
     9 using namespace std;
    10 
    11 int n,m,tot;
    12 int a[N];
    13 bool v[N];
    14 vector<int> cir[N];
    15 
    16 int main()
    17 {
    18     while(~scanf("%d",&n))
    19     {
    20         for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    21         scanf("%d",&m);
    22         m=n-m;
    23         for(int i=1;i<=n;i++) v[i]=0;
    24         tot=0;
    25         for(int i=1;i<=n;i++)
    26         {
    27             if(v[i]) continue;
    28             int tmp=i;
    29             cir[++tot].clear();
    30             while(!v[tmp])
    31             {
    32                 v[tmp]=1;
    33                 cir[tot].push_back(tmp);
    34                 tmp=a[tmp];
    35             }
    36         }
    37         if(tot==m) cout<<0<<endl;
    38         else if(tot>m)
    39         {
    40             cout<<tot-m<<endl;
    41             for(int Te=1;Te<=tot-m;Te++)
    42             {
    43                 int t=0;
    44                 for(int i=2;i<=tot;i++)
    45                     if(!cir[i].empty() && (!t || cir[i][0]<cir[t][0]))
    46                         t=i;
    47                 cout<<cir[1][0]<<' '<<cir[t][0]<<' ';
    48                 for(int i=0;i<(int)cir[t].size();i++)
    49                     cir[1].push_back(cir[t][i]);
    50                 cir[t].clear();
    51             }
    52         }
    53         else
    54         {
    55             int tott=tot;
    56             cout<<m-tot<<endl;
    57             for(int Te=1;Te<=m-tot;Te++)
    58             {
    59                 int t=0;
    60                 for(int i=1;i<=tott;i++)
    61                     if(cir[i].size()>1 && (!t || cir[i][0]<cir[t][0]))
    62                         t=i;
    63                 int pos=1;
    64                 for(int i=2;i<(int)cir[t].size();i++)
    65                     if(cir[t][i]<cir[t][pos])
    66                         pos=i;
    67                 cout<<cir[t][0]<<' '<<cir[t][pos]<<' ';
    68                 swap(cir[t][0],cir[t][pos]);
    69                 cir[++tott].clear();
    70                 int cnt=0;
    71                 for(int i=pos;i<(int)cir[t].size();i++)
    72                     cir[tott].push_back(cir[t][i]),cnt++;
    73                 while(cnt--) cir[t].pop_back();
    74             }
    75         }
    76     }
    77     return 0;
    78 } 
    View Code
  • 相关阅读:
    stream流的统计demo
    ResourceBundle 读取文件demo
    spring boot 配置Filter过滤器的两种方式
    java工厂模式demo
    ThreadLocalDemo
    观察者模式Demo
    大数字的计算
    rabbitMQ消息丢失
    CF671E(线段树+单调栈)
    2020集训队作业板刷记录(三)
  • 原文地址:https://www.cnblogs.com/lawyer/p/6575936.html
Copyright © 2011-2022 走看看