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],的最大值。

转移方程:因为要求最大值,单纯的用素数的积并不能得到最大值,最大值得形式是prime[1]^s1*prime[2]^s2*...*prime[25]^s25

for(int i=1;i<=cnt;i++)
        {
            long long tmp[110];
            for(int j=0;j<=n;j++)
                tmp[j]=dp[j];
            for(int k=1;mypow(saveprime[i],k)<=n;k++)
            {
                long long tmpnum=mypow(saveprime[i],k);
                for(int j=tmpnum;j<=n;j++)
                {
                    dp[j]=max(tmp[j-tmpnum]*tmpnum,dp[j]);
                }
            }
        }

The shuffle Problem

Time Limit: 3000MS   Memory Limit: 65536K
Total Submissions: 1882   Accepted: 626

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

2
1
5

Sample Output

1 1
6 2 1 4 5 3
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
using namespace std;

int saveprime[30];
long long dp[110];
int saveans[110];
int mypow(int x,int y)
{
    int sum=1;
    for(int i=1;i<=y;i++)
        sum*=x;
    return sum;
}

int main()
{
    int cnt=0;
    for(int i=2;i<=100;i++)
    {
        int flag=0;
        for(int j=2;j<i;j++)
        {
            if(i%j==0)
            {
                flag=1;
                break;
            }
        }
        if(flag==0)
        {
            saveprime[++cnt]=i;
        }
    }

    int T;
    cin>>T;
    while(T--)
    {
        int n;
        cin>>n;
        for(int i=0;i<=n;i++)
            dp[i]=1;
        for(int i=1;i<=cnt;i++)
        {
            long long tmp[110];
            for(int j=0;j<=n;j++)
                tmp[j]=dp[j];
            for(int k=1;mypow(saveprime[i],k)<=n;k++)
            {
                long long tmpnum=mypow(saveprime[i],k);
                for(int j=tmpnum;j<=n;j++)
                {
                    dp[j]=max(tmp[j-tmpnum]*tmpnum,dp[j]);
                }
            }
        }
        cout<<dp[n];
        long long mx=dp[n];
        int anscnt=0;
        int anssum=0;
        for(int i=0;i<100;i++)
            saveans[i]=1;
        for(int i=1;i<=cnt;i++)
        {
            int sign=0;
            while(mx%saveprime[i]==0)
            {
                saveans[anscnt] *= saveprime[i];
                mx /= saveprime[i];
                sign=1;
            }
            if(sign==1)
            {
                anssum += saveans[ anscnt ];
                anscnt++;
            }
        }
        sort(saveans,saveans+anscnt);

        //printf("\n");
        //for(int i=0;i<anscnt;i++)
            //printf("%d ",saveans[i]);
        //printf("\n");
        for(int i=1;i<=n-anssum;i++)
        {
            printf(" %d",i);
        }
        int pos=n-anssum;
        for(int i=0;i<anscnt;i++)
        {
            for(int j=2;j<=saveans[i];j++)
                printf(" %d",pos+j);
            printf(" %d",pos+1);
            pos+=saveans[i];
        }
        printf("\n");
    }
    return 0;
}
时间: 2024-08-07 00:17:37

poj 3590(dp 置换)的相关文章

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

HDU 1087 &amp;&amp; POJ 2533(DP,最长上升子序列).

~~~~ 两道题的意思差不多,HDU上是求最长上升子序列的和,而POJ上就的是其长度. 貌似还有用二分写的nlogn的算法,不过这俩题n^2就可以过嘛.. ~~~~ 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1087 http://poj.org/problem?id=2533 ~~~~ HDU1087: #include<cstdio> #include<cstring> #include<algorithm> #

poj 2369 Permutations 置换水题

找循环节求lcm就够了,若答案是12345应该输出1,被坑了下. #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<cmath> using namespace std; #define INF 0x3FFFFFF #define MAXN 2222 #define eps 1e-6 i

POJ 3670 &amp;&amp; POJ 3671 (dp)

最长不下降子序列的应用嘛.两题都是一样的. POJ 3670:求给定序列按递增或递减排列时,所需改变的最小的数字的数目. POJ 3671:求给定序列按递增排列时,所需改变的最小的数字的数目. 思路就是求最长不下降子序列,然后剩下的就是需要改变的字母. 最长不下降子序列:(我之前有写过,不懂请戳)http://blog.csdn.net/darwin_/article/details/38360997 POJ 3670: #include<cstdio> #include<cstring

poj 3783 DP 2个鸡蛋扔100层楼的加强版

http://poj.org/problem?id=3783 估计23号之后的排位赛之后我就要退役了,这之前最后再做5天ACM 今天的排位很惨,上次排位也很惨......这道题原来算法课老师讲过,模模糊糊记得方程,但是边界处理有问题, dp[i][j]=min(1+max(dp[k-1][j-1],dp[i-k][j]))   k=1 to 楼数 dp[i][j]:i层楼扔,手里有j个ball 的次数 边界两个:1.dp[1][i]=1,第一层无论手里有几个鸡蛋都是1次,2.dp[i][1]=i

POJ 3034 DP

打地鼠游戏中,你有一个锤子,每一秒钟你可以拿着锤子移动d个单位的距离,必须是直线,掠过的鼠洞中露出的地鼠都会被锤打至,而事先知道从开始时各时间段内出现在老鼠的数量和位置,问题是从游戏开始至结束时,你最多能打到多少只地鼠,开始时锤子可以在任何位置. 题目有个陷阱, 只是说Moles出现的坐标为正,但没说hammer移动的位置要为正,可以为"any position" 所以锤子可以移出矩阵,再从矩阵外一点移进来 例: 20 5 4 1 0 1 0 1 1 0 5 2 1 6 2 0 0 0

POJ 4968 DP||记忆化搜索

给出N个人的平局分X 根据GPA规则计算可能的最高平均GPA和最低平均GPA 可以DP预处理出来所有结果  或者记忆化搜索 DP: #include "stdio.h" #include "string.h" int inf=100000000; double a[11][1100],b[11][1100]; double Max(double a,double b) { if (a<b) return b; else return a; } double M

POJ 2029 DP || 暴力

在大矩形中找一个小矩形 使小矩形包含的*最多 暴力或者DP  水题 暴力: #include "stdio.h" #include "string.h" int main() { int n,m,w,i,s,t,j,k,l,ans,sum,x,y; int map[101][101]; while (scanf("%d",&w)!=EOF) { if(w==0) break; scanf("%d%d",&n,&

poj 1721 CARDS(置换)

http://poj.org/problem?id=1721 大致题意:原始序列通过洗牌机洗牌s次后变为当前序列,已知当前序列,求原始序列. 在置换群快速幂运算 研究与探讨中最后有详解,有两种解法,一种是求出置换的长度a(即一副牌洗a次后变回原来的位置),现已知原始序列置换s次变为当前序列,那么当前序列再置换a-s次就是原始序列了.求a就是直接模拟每个置换的过程,直到某序列与当前序列相等.另一种是置换的开方,相当于原始序列的2^s幂是当前序列,将当前序列开2^s次方便是原始序列. 第二种方法暂时