置换的概念还是比较好理解的,《组合数学》里面有讲。对于置换的幂运算大家可以参考一下潘震皓的那篇《置换群快速幂运算研究与探讨》,写的很好。
结论一:一个长度为 L 的循环 T,L 是 k 的倍数,则 Tk 是k个循环的乘积,每个循环分别是循环 T 中下标 i mod k= 0,1,2…的元素按顺序的连接。
结论二:一个长度为 L 的循环T,gcd(L,k)=1,则 Tk 是一个循环,与循环 T 不一定相同。
结论三:一个长度为 L 的循环T, 是gcd(L,k)个循环的乘积,每个循环分别是循环 T 中下标 i mod gcd(l,k)=0,1,2…的元素的连接。
如果长度与指数不互质,单个循环就没有办法来开方。不过,我们可以选择相应m个长度相同的循环交错合并来完成开方的过程。可在这种情况下,如果找不到m个长度相同的循环,那就一定不能开方。其中:m是gcd(l,k)的倍数
POJ 3270 Cow Sorting http://poj.org/problem?id=3270
Description
Farmer John’s N (1 ≤ N ≤ 10,000) cows are lined up to be milked in the evening. Each cow has a unique “grumpiness” level in the range 1…100,000. Since grumpy cows are more likely to damage FJ’s milking equipment, FJ would like to reorder the cows in line so they are lined up in increasing order of grumpiness. During this process, the places of any two cows (not necessarily adjacent) can be interchanged. Since grumpy cows are harder to move, it takes FJ a total of X+Y units of time to exchange two cows whose grumpiness levels are X and Y.
Please help FJ calculate the minimal time required to reorder the cows.
Input
Line 1: A single integer: N.
Lines 2…N+1: Each line contains a single integer: line i+1 describes the grumpiness of cow i.
Output
Line 1: A single line with the minimal time required to reorder the cows in increasing order of grumpiness.
Sample Input
3
2
3
1
Sample Output
7
Hint
2 3 1 : Initial order.
2 1 3 : After interchanging cows with grumpiness 3 and 1 (time=1+3=4).
1 2 3 : After interchanging cows with grumpiness 1 and 2 (time=2+1=3).
题意的话,给你一个数字序列(每个数字唯一),每次你可以交换任意两个数字,代价为这两个数字的和,问最少代价能把这个序列按升序排列好。
#include
using namespace std;
typedef long long ll;
typedef unsigned long long llu;
const int inf = 0x3f3f3f3f;
const ll lnf = 0x3f3f3f3f3f3f3f3f;
const int maxn = 100100;
int a[maxn],b[maxn],c[maxn];
bool p[maxn];
int main(void)
{
int n;
while(~scanf("%d",&n)){
ll ans = 0;
memset(p,false,sizeof(p)); //标记数组
for(int i=0;i<n;i++){
scanf("%d",a+i);
ans += (ll)a[i];
b[i] = a[i];
}
sort(b,b+n);
for(int i=0;i<n;i++)
c[b[i]] = i;
int len,_min,st,id;
ll ans1,ans2;
for(int i=0;i<n;i++){
id = i;
st = a[i];
_min = inf;
len = 0;
if(!p[i]){
while(1){
p[id] = true;
if(_min>st) _min = st;
len++;
id = c[st];
st = a[id];
if(st==a[i]) break;
}
ans1 = (ll)(len-2)*_min;
ans2 = (ll)_min + (ll)(len+1)*b[0];
ans += min(ans1,ans2);
}
}
printf("%lld\n",ans);
}
return 0;
}