POJ3590,循环群构造(dfs做法)

The shuffle Problem
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

这道题,大概就是给你n,然后让你构造出整个序列的最大循环节长度。
对整个序列,我们可以将他们划分为若干个序列,n1, n2, n3,那么整个序列的循环节长度就是所有lcm(n1, n2, n3…)(显然)
由于求lcm,如果我们每次都用同样的n1, n1, n1,lcm是最小的,因此排除这种情况,这就是进行dfs搜索的前提。
边搜索的时候,边计算lcm,剪枝。
网上有dp预处理最大lcm的方法,看了好多,抄的一模一样不想吐槽了。
这道题对我加深循环群的理解还是挺有帮助的。。
trick还是比较多,注意字典序输出,注意无贡献的ni要拆成1
代码如下:

//
//  Created by Running Photon on 2015-09-17
//  Copyright (c) 2015 Running Photon. All rights reserved.
//
//
//#pragma comment(linker, "/STACK:102400000,102400000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <sstream>
#include <set>
#include <vector>
#include <stack>
#define ALL(x) x.begin(), x.end()
#define INS(x) inserter(x, x,begin())
#define ll long long
#define CLR(x) memset(x, 0, sizeof x)
#define MAXN 9999
#define MAXSIZE 10
#define DLEN 4
using namespace std;
const int inf = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int maxn = 1e6 + 10;
const int maxv = 1e3 + 10;
const double eps = 1e-9;


inline int read() {
    char c = getchar();
    int f = 1;
    while(!isdigit(c)) {
    if(c == '-') f = -1;
    c = getchar();
    }
    int x = 0;
    while(isdigit(c)) {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x * f;
}
int t, n;
ll big = 0;
int top;
int cir[maxv];
int tmp[maxv];
ll lcm(ll a, ll b) {
    return a / __gcd(a, b) * b;
}
void dfs(int id, int res, int from, ll l) {
    if(!res) {
//      ll l = 1;
//      for(int i = 0; i < id; i++) {
//          l = lcm(l, tmp[i]);
//      }
        if(big < l) {
            big = l;
            for(int i = 0; i < id; i++)
                cir[i] = tmp[i];
            top = id;
        }
        return;
    }
    if(res <= from) {
        tmp[id] = res;
        ll temp = l;
        l = lcm(l, res);
        dfs(id + 1, 0, from, l);
        l = temp;
    }
    else {
        for(int i = from; i <= res; i++) {
            tmp[id] = i;
            ll temp = l;
            l = lcm(l, i);
            dfs(id + 1, res - i, i + 1, l);
            l = temp;
        }
    }
}
int ans[maxv];
int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
//  freopen("out.txt","w",stdout);
#endif
    scanf("%d", &t);
    while(t--) {
        big = 0;
        top = 0;
        scanf("%d", &n);
        if(n == 1) {puts("1 1"); continue;}
        dfs(0, n, 1, 1);
        for(int i = 1; i <= n; i++)
            ans[i] = i;
        int id = 1;
        sort(cir, cir + top);
        vector <int> v;
        for(int i = 0; i < top; i++) {
            int flag = 0;
            for(int j = i + 1; j < top; j++) {
                if(cir[j] % cir[i] == 0) flag = 1;
            }
            if(flag) while(cir[i]--) v.push_back(1);
            else v.push_back(cir[i]);
        }
        sort(ALL(v));
        for(int i = 0; i < v.size(); i++) {
            for(int j = id; j < v[i] + id - 1; j++) {
                swap(ans[j], ans[j+1]);
            }
            id += v[i];
        }
//      for(int i = 0; i < v.size(); i++)
//          printf("%d ", v[i]);
//      puts("");
        printf("%I64d", big);
        for(int i = 1; i <= n; i++)
            printf(" %d", ans[i]);
        puts("");
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值