POJ 3590
题意:给出一个整数n,叫你给出1到n的某个序列经过k次置换后能还原,求这样最大的k,如果存在多种序列满足要求。
则必须求出字典序最小的那个序列。
一个轮换必须经过它的大小的次数的置换才能还原,那么这个序列的k其实就是它的所有轮换的大小的最小公倍数。至于怎么求
最小序列,可以通过素数分解来完成。
View Code
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #define MAXN 104 5 using namespace std; 6 __int64 dp[MAXN][MAXN]; 7 __int64 gcdmax[MAXN]; 8 __int64 Div[MAXN]; 9 int prime[25] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 10 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97}; 11 int cnt; 12 13 __int64 gcd(__int64 x, __int64 y) 14 { 15 if (min(x,y) == 0)return max(x,y); 16 return gcd(y,x%y); 17 } 18 19 void prepare() 20 { 21 for (int i(1); i<=100; ++i) { 22 dp[i][1] = i; 23 } 24 25 for (int i(2); i<=100; ++i) { 26 for (int j(2); j<=i; ++j) { 27 for (int k(1); k<i && (i-k)>=(j-1); ++k) { 28 dp[i][j] = max(dp[i][j],dp[i-k][j-1]*k/gcd(dp[i-k][j-1],k)); 29 } 30 } 31 } 32 33 for (int i(1); i<=100; ++i) { 34 for (int j(1); j<=i; ++j) { 35 gcdmax[i] = max(gcdmax[i],dp[i][j]); 36 } 37 } 38 } 39 40 void deal(__int64 num) 41 { 42 cnt = 0; 43 for (int i(0); i<25; ++i) { 44 if (num%prime[i])continue; 45 Div[cnt] = 1; 46 while (num%prime[i] == 0) { 47 Div[cnt] *= prime[i]; 48 num /= prime[i]; 49 } 50 ++cnt; 51 } 52 } 53 54 55 int main() 56 { 57 int t; 58 prepare(); 59 scanf("%d",&t); 60 while (t--) { 61 int n; 62 scanf("%d",&n); 63 cout<<gcdmax[n]; 64 deal(gcdmax[n]); 65 sort(Div,Div+cnt); 66 int sum = 0; 67 for (int i(0); i<cnt; ++i) { 68 sum += Div[i]; 69 } 70 sum = n - sum; 71 for (int i(1),j(0),k(0); i<=n; ++i) { 72 if (sum) { 73 cout<<" "<<i; 74 sum--; 75 } else { 76 for (j = 1; j<Div[k]; ++j) { 77 cout<<" "<<i+j; 78 } 79 ++k; 80 cout<<" "<<i; 81 i += (j-1); 82 } 83 } 84 cout<<endl; 85 } 86 return 0; 87 }