A permutation p of length n is a sequence of distinct integers p1, p2, ..., pn (1 ≤ pi ≤ n). A permutation is an identity permutation, if for any i the following equation holds pi = i.
A swap (i, j) is the operation that swaps elements pi and pj in the permutation. Let's assume that f(p) is the minimum number of swaps that you need to make the permutation p an identity permutation.
Valera wonders, how he can transform permutation p into any permutation q, such that f(q) = m, using the minimum number of swaps. Help him do that.
The first line contains integer n (1 ≤ n ≤ 3000) — the length of permutation p. The second line contains n distinct integersp1, p2, ..., pn (1 ≤ pi ≤ n) — Valera's initial permutation. The last line contains integer m (0 ≤ m < n).
In the first line, print integer k — the minimum number of swaps.
In the second line, print 2k integers x1, x2, ..., x2k — the description of the swap sequence. The printed numbers show that you need to consecutively make swaps (x1, x2), (x3, x4), ..., (x2k - 1, x2k).
If there are multiple sequence swaps of the minimum length, print the lexicographically minimum one.
5 1 2 3 4 5 2
2 1 2 1 3
5 2 1 4 5 3 2
1 1 2
Sequence x1, x2, ..., xs is lexicographically smaller than sequence y1, y2, ..., ys, if there is such integer r (1 ≤ r ≤ s), thatx1 = y1, x2 = y2, ..., xr - 1 = yr - 1 and xr < yr.
大致题意:n的排列(n<3000) 输出字典序最小的两两元素交换方案,使交换后的排列最少交换m次可以变成“原始排列pi = i”
思路:想了好久想不到“一个排列最少经过几次交换可以变成原始排列”这个问题,如果仅仅交换相邻元素的话就和逆序数有关了再用线段树乱搞搞就好了
然后得知有个知识叫“置换群”--http://www.cnblogs.com/buptLizer/archive/2011/11/15/2249551.html
然后需要理解这几点就可以做题辣:
1.一个大小为L的置换群里面的元素至少且必能互换L-1次得到原始排列
2.分别任取两个置换群的元素交换一次将合并成一个置换群(这个是显然正确的)
3.在一个置换群里面任取两个元素交换一次将分裂成两个置换群(这个证明不是很显然)
接下来,做这题就是暴力了= =,用2来暴力减少置换群,用1来暴力增加置换群就ok辣
#include <iostream> #include <cstring> #include <cmath> #include <queue> #include <stack> #include <list> #include <map> #include <set> #include <sstream> #include <string> #include <vector> #include <cstdio> #include <ctime> #include <bitset> #include <algorithm> #define SZ(x) ((int)(x).size()) #define ALL(v) (v).begin(), (v).end() #define foreach(i, v) for (__typeof((v).begin()) i = (v).begin(); i != (v).end(); ++ i) #define REP(i,n) for ( int i=1; i<=int(n); i++ ) using namespace std; typedef long long ll; const int N = 3000+100; const int inf = 0x3f3f3f3f; int a[N]; int fa[N]; int pos[N]; int getf(int x){ return x == fa[x] ? x:fa[x] = getf(fa[x]); } void dfs(int u,int pa){ if(pa != -1 && getf(a[u]) == getf(pa)) return; int v = a[u]; fa[v] = getf(u); dfs(v,u); } pair<int,int> ans; typedef pair<int,int> pii; void solve(int u,int pa,int rt){ if(pa != -1 && getf(a[u]) == getf(pa)) return ; int v = a[u]; if(v == u) return ; if(ans > pii(rt,v)) ans = pii(rt,v); fa[v] = getf(u); solve(v,u,rt); } int cnt[N]; int main(){ int n; cin>>n; REP(i,n)fa[i] = i; REP(i,n) scanf("%d",&a[i]),pos[a[i]] = i; int m; cin>>m; REP(i,n) if(getf(i) == i) dfs(i,-1); REP(i,n) cnt[getf(i)]++; int cur = 0; REP(i,n) if(cnt[i]) cur += cnt[i]-1; int nd = cur-m; printf("%d\n",abs(nd)); if(nd > 0){ while(nd--){ ans = pii(inf,inf); REP(i,n) fa[i] = i; REP(i,n) if(getf(i) == i) solve(i,-1,i); printf("%d %d ",ans.first,ans.second); swap(a[ans.first],a[ans.second]); } } else { nd = -nd; cnt[getf(1)] = 0; for(int p = 2;p <= n && nd;p++){ if(cnt[getf(p)]) { printf("%d %d ",1,p); nd--; cnt[getf(p)] = 0; } } } }