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 }