poj 3590


题目大意:

k 为满足 Pk=e 的最小的非负整数 。

构造出长度为 n 的置换 P,使得 k 最大,

若有多个置换 k 值相同,输出字典序最小的。


pi P 的循环长度。那么 k=lcm(p1p2p3...pt)

1.考虑 p1 p2 lcm(p1,p2)=p1p2gcd(p1,p2)
根据贪心, gcd(p1,p2)=1 时是最优的,此时 k=ti=1pi

2.考虑 p11 , p21 gcd(p1,p2)=1

如果把 p1 p2 合并成一个置换,长度为 p1+p2

那么它对答案贡献为 p1+p2<p1p2

所以长度不为 1 的置换合并之后反而不是更优的。

综上所述,pi 为质数的幂或者 1 是最优的。


求出 pi 之后构造置换,根据贪心的原则,按循环长度从小到大构造答案即可。


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <utility>
#include <iostream>
#include <algorithm>

template<class Num>void read(Num &x)
{
    char c; int flag = 1;
    while((c = getchar()) < '0' || c > '9')
        if(c == '-') flag *= -1;
    x = c - '0';
    while((c = getchar()) >= '0' && c <= '9')
        x = (x<<3) + (x<<1) + (c-'0');
    x *= flag;
    return;
}
template<class Num>void write(Num x)
{
    if(x < 0) putchar('-'), x = -x;
    static char s[20];int sl = 0;
    while(x) s[sl++] = x%10 + '0',x /= 10;
    if(!sl) {putchar('0');return;}
    while(sl) putchar(s[--sl]);
}
#define REP(__i,__start,__end) for(int __i = (__start); __i <= (__end); __i++)

const int tot = 25, size = 30;

int prime[size] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97};  

long long maxlcm;
int n, c[size], p[size];

void dfs(int s,int rem,long long lcm)
{
    if(s == tot + 1)
    {
        if(lcm > maxlcm)
        {
            maxlcm = lcm;
            REP(i, 1, tot) c[i] = p[i];
        }
        return;
    }

    int calc = prime[s];

    p[s] = 0, dfs(s + 1, rem, lcm);

    while(calc <= rem)
    {
        p[s] = calc;
        dfs(s + 1, rem - calc, lcm * calc);
        calc *= prime[s];
    }
}

void output()
{
    int pl = 0, rm = n, pos;

    write(maxlcm), putchar(' ');

    REP(i, 1, tot)
        if(c[i])
        {
            p[++pl] = c[i];
            rm -= c[i];
        }

    REP(i, 1, rm) write(i), putchar(' ');

    pos = rm;

    std::sort(p + 1, p + pl + 1);

    REP(i, 1, pl)
    {
        REP(j, 2, p[i])
        {
            write(pos + j);
            putchar(' ');
        }

        write(pos + 1);
        putchar(' ');

        pos += p[i];
    }

    puts("");
}

int main()
{
    int T;
#ifndef ONLINE_JUDGE    
    freopen("3590.in","r",stdin);
    freopen("3590.out","w",stdout);
#endif

    read(T);

    while(T--)
    {
        memset(c, 0, sizeof(c));

        read(n);

        maxlcm = 0, dfs(1, n, 1);

        output();
    }

#ifndef ONLINE_JUDGE    
    fclose(stdin);
    fclose(stdout);
#endif
    return 0;
}

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值