poj 3590 The shuffle Problem(置换群+DP)

题目链接:poj 3590 The shuffle Problem

题意:

给你一个数n,让你找一个字典序最小的置换序列,使得变换整个周期最大。

题解:

由于置换群的性质,我们可以将n拆分成m个数,使得这m个数的和为n,并且这m个数的最小公倍数最大。

dp可以求出将n拆分后的最大的最小公倍数。

然后可以将这个最大的最小公倍数分解为pi^mi+pi^mi+pi^mi...。

对于每一个pi^mi,就是一个循环的轮数。

然后将这些循环的轮数排序后输出对于的数字就行了。

PS:当前面的总和sum小于n时,前n-sum的循环轮数就全是1,这些数不会影响最大的最小公倍数。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define F(i,a,b) for(int i=a;i<=b;++i)
 5 using namespace std;
 6 typedef long long ll;
 7
 8 const int N=101;
 9
10 int primes[N+1],tot=0;
11 bool vis[N+1];
12 void Euler(){
13     memset(vis,0,sizeof(vis));
14     F(i,2,N){
15         if(!vis[i])primes[++tot]=i;
16         F(j,1,tot){
17             if(i*primes[j]>N)break;
18             vis[i*primes[j]]=1;
19             if(i%primes[j]==0)break;
20         }
21     }
22 }
23
24 int dp[N][N],mx[N],cnt,tmp,t,sum,n,ans[N];
25
26 void init()
27 {
28     F(i,1,100)F(j,1,100)dp[i][1]=i;
29     F(i,1,100)
30     {
31         F(j,1,i)
32         {
33             F(k,1,i-1)
34             {
35                 int tmp=dp[i-k][j-1]*k/__gcd(dp[i-k][j-1],k);
36                 if(dp[i][j]<tmp)dp[i][j]=tmp;
37             }
38         }
39         F(j,1,i)mx[i]=max(dp[i][j],mx[i]);
40     }
41 }
42
43 int main()
44 {
45     Euler(),init();
46     scanf("%d",&t);
47     while(t--)
48     {
49         scanf("%d",&n);
50         tmp=mx[n],sum=cnt=0;
51         printf("%d",mx[n]);
52         int tmp=mx[n],tp;
53         F(i,1,25)
54         {
55             if(primes[i]>tmp)break;
56             if(tmp%primes[i]==0)
57             {
58                 tp=1;
59                 while(tmp%primes[i]==0)tmp/=primes[i],tp*=primes[i];
60                 ans[++cnt]=tp,sum+=tp;
61             }
62         }
63         sort(ans+1,ans+1+cnt);
64         F(i,1,n-sum)printf(" %d",i);
65         int now=1,num=ans[now],ct=0;
66         F(i,n-sum+1,n)
67         {
68             if(ct==num-1)
69                 printf(" %d",i-ct),ct=0,num=ans[++now];
70             else printf(" %d",i+1),ct++;
71         }
72         puts("");
73     }
74     return 0;
75 }

时间: 2024-10-08 10:29:21

poj 3590 The shuffle Problem(置换群+DP)的相关文章

poj 3590(dp 置换)

题目的意思是对于序列1,2,...,n.要你给出一种字典序最小的置换使得经过X次后变成最初状态,且要求最小的X最大. 通过理解置换的性质,问题可以等价于求x1,x2,..,xn 使得x1+x2+...+xk=n,且GLM(x1,x2,...,xn)最大. 这个就用dp来做,首先求出100内的所有素数记录为prime[1] 到 prime[25]. 状态:dp[i][j] 表示花费了i,且已经使用prime[1] 到 prime[j],的最大值. 转移方程:因为要求最大值,单纯的用素数的积并不能得

POJ 3254 Corn Fields 状态压缩DP (C++/Java)

http://poj.org/problem?id=3254 题目大意: 一个农民有n行m列的地方,每个格子用1代表可以种草地,而0不可以.放牛只能在有草地的,但是相邻的草地不能同时放牛, 问总共有多少种方法. 思路: 状态压缩的DP. 可以用二进制数字来表示放牧情况并判断该状态是否满足条件. 这题的限制条件有两个: 1.草地限制. 2.相邻限制. 对于草地限制,因为输入的时候1是可以种草地的. 以"11110"草地分析,就只有最后一个是不可以种草的.取反后得00001  .(为啥取反

POJ 1185 炮兵阵地 状压dp

http://poj.org/problem?id=1185 经典题目不必多说,直接贴代码. 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 int n, m, cnt, size; 7 int a[110], st[70], ct[70]; 8 char str[15]; 9 int f[110][70][70]; 10 void init(

POJ 3132 Sum of Different Primes DP背包

http://poj.org/problem?id=3132 题意: 给定n和k,问用恰好k个不同的质数来表示n的方案数. 分析: n和k都很小.反正就是个背包,选k个物品恰好填满n即可. 1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 5 bool dp[1200][15]; 6 int ct[1200][15]; 7 int p[1200]; 8 bool a[1200]; 9 int n, k,

poj 4045 Power Station(初涉树形dp)

http://poj.org/problem?id=4045 大致题意:有n个村庄,求将发电站建在哪一个村庄使得花费最少.这是一个无向无环图.简化一下就是求一个节点使它到其他所有节点的距离和最小. 起初一直在向最短路上靠,但因为节点和边数太大,必定TLE.然后无比强大的啸神随便写了两个dfs就过掉了,简直膜拜.赛后搜了搜题解,发现这是道树形dp.sad,真的要好好刷dp了. 大体思路是将这个无向无环图看做一个树,我们就在这个树上进行动态规划.首先先随便拿一个节点看做根节点(假设节点1),计算出它

poj 3270 Cow Sorting(初涉置换群)

http://poj.org/problem?id=3270 大致题意:给出n个整数,要将它们转化成递增序列,每交换其中两个数的代价是这两个数之和.问排序成功后的最小代价. 该题考察的是置换群知识.在黑书p247上有详细的讲解.总结下置换群,方便复习. 群:给定一个集合G={a,b,c...}和集合G上的二元运算 ·,如果满足封闭性,结合律,存在单位元和逆元,则成集合G在运算'·'之下是一个群. 置换:n个元素1,2,....,n之间的置换可表示为  1     2     3     ...

POJ 3071 Football (动态规划-概率DP)

Football Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 2768   Accepted: 1412 Description Consider a single-elimination football tournament involving 2n teams, denoted 1, 2, -, 2n. In each round of the tournament, all teams still in the

POJ 1651 Multiplication Puzzle (区间dp)

题目大意:对n个数组成的序列取数,规定最两边不能取,每次取一个a[i],得到 a[l] * a[i] * a[r] 的分数(a[l]是a[i]左边的数,a[r]是a[i]右边的数),并把这个数从序列中移走,求n-2次取数后的得分和的最小值 分析:正着确定状态不好做,不如反着来,设dp[l][r]为向区间[l, r]中填满数所得到分数和的最小值,考虑最近一次填数的位置,不难得出: dp[l][r] = fmin(dp[l][m] + dp[m][r] + a[l] * a[m] * a[r]) (

树的点分治 (poj 1741, 1655(树形dp))

poj 1655:http://poj.org/problem?id=1655 题意: 给无根树,  找出以一节点为根,  使节点最多的树,节点最少. 题解:一道树形dp,先dfs 标记 所有节点的子树的节点数. 再dfs  找出以某节点为根的最大子树,节点最少. 复杂度(n) /***Good Luck***/ #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <cstdio> #include <cs