poj 3590 The shuffle Problem (置换+分组背包)

来源:互联网 发布:房屋装修甲醛检测数据 编辑:程序博客网 时间:2024/06/04 20:14

The shuffle Problem
Time Limit: 3000MS Memory Limit: 65536KTotal Submissions: 2115 Accepted: 702

Description

Any case of shuffling of n cards can be described with a permutation of 1 to n. Thus there are totally n! cases of shuffling. Now suppose there are 5 cards, and a case of shuffle is <5, 3, 2, 1, 4>, then the shuffle will be:

Before shuffling:1, 2, 3, 4, 5
The 1st shuffle:5, 3, 2, 1, 4
The 2nd shuffle:4, 2, 3, 5, 1
The 3rd shuffle:1, 3, 2, 4, 5
The 4th shuffle:5, 2, 3, 1, 4
The 5th shuffle:4, 3, 2, 5, 1
The 6th shuffle:1, 2, 3, 4, 5(the same as it is in the beginning)

You'll find that after six shuffles, the cards' order returns the beginning. In fact, there is always a number m for any case of shuffling that the cards' order returns the beginning after m shuffles. Now your task is to find the shuffle with the largest m. If there is not only one, sort out the one with the smallest order.

Input

The first line of the input is an integer T which indicates the number of test cases. Each test case occupies a line, contains an integer n (1 ≤ n ≤ 100).

Output

Each test case takes a line, with an integer m in the head, following the case of shuffling.
 

Sample Input

215

Sample Output

1 16 2 1 4 5 3

Source

South Central China 2008 hosted by NUDT

[Submit]   [Go Back]   [Status]   [Discuss]


题目大意:一个置换作多次后就可以回到最初的状态,假设这个次数成为循环节。那么这道题就是要求最大的循环节x,并且构造循环节为x的字典序最小的方案。

题解:置换+分组背包

这道题的做法与bzoj 1025是类似的。只不过我们还有开一个数组记录每一步的选择,在逆推回去。然后将轮换的长度从小到大排序,从1..n依次满足每个轮换。例如第一个轮换的长度是3,那么就输出(2,3,1)

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#define N 230using namespace std;int T,n,pd[N],prime[N],f[N][N],g[N][N],num[N],cnt;void init(int n){for (int i=2;i<=n;i++) {if (!pd[i]) prime[++prime[0]]=i;for (int j=1;j<=prime[0];j++){if (prime[j]*i>n) break;pd[prime[j]*i]=1;if (i%prime[j]==0) break;}}}int main(){freopen("a.in","r",stdin);scanf("%d",&T);init(100);while (T--){scanf("%d",&n);memset(f,0,sizeof(f));memset(g,0,sizeof(g));f[0][0]=1;for (int i=1;i<=prime[0];i++) for (int j=n;j>=0;j--) { f[i][j]=f[i-1][j]; g[i][j]=0; int now=prime[i]; while (j>=now) { if (f[i][j]<f[i-1][j-now]*now)  f[i][j]=f[i-1][j-now]*now,g[i][j]=now; now*=prime[i]; } }int ans=0,pos=0;int t=prime[0];for (int i=0;i<=n;i++) if (f[t][i]>ans) { ans=f[t][i]; pos=i; }printf("%d ",ans); int l=n-pos+1;for (int i=1;i<=n-pos;i++) printf("%d ",i);cnt=0; int j=pos;for (int i=prime[0];i>=1;i--) {if (g[i][j]) num[++cnt]=g[i][j];j-=g[i][j];}sort(num+1,num+cnt+1); for (int i=1;i<=cnt;i++) {for (int j=l;j<=l+num[i]-2;j++) printf("%d ",j+1);printf("%d ",l);l+=num[i];}printf("\n");}}



0 0
原创粉丝点击