题目



解析

很神奇的一道题

显然,对于一种排列,相当于给出了数字 \(1..n\) 的对应关系,且不重复不遗漏,刚好把 \(1\) 到 \(n\) 又包含了一遍。

对,连边!

每个数向它对应的数连边,这样我们就得到了一幅图,且这幅图很有特点——全是简单环。

因为每个数的对应有且仅有一个,且不重复不遗漏,所以不存在大环套小环的情况,不存在复杂图形,而且,由于连了边,每个点是什么数字已经没有意义了。

显然,对于一个排列,最大的秩就是所有环大小的最小公倍数。

把 \(n\) 拆成几个正整数的和(正整数可以为 \(1\)),这些正整数的最小公倍数就是我们要的最大的秩,而字典序最小的拆法就是我们要输出的东西。

既然我们已经知道答案就是某个最小公倍数,那我们为什么不直接构造这个最小公倍数?

最小公倍数归根到底是很多质数的乘积,因此我们直接用质数来构造。

假设现在有三个质数 \(p_1、p_2、p_3\),它们的和 \(\leq n\),那么 \(p_1*p_2*p_3\) 一定是一个合法的答案。我们可以先弄一个大小为 \(p_1\) 的环,然后弄一个大小为 \(p_2\) 的环,再弄大小为 \(p_3\) 的环,如果n还有剩余,那么剩下的通通自环,这样一定是合法的。

推广:现在把三个质数变成 \(p1^{c1}、p2^{c2}、p3^{c3}\),他们乘起来依然是合法的。跟上面其实是一样的道理。

再推广:设环的大小为 \(w\),那么 \(w\) 可不可以包含两种或以上素数?可以,但是完全可以转化成上面的情况处理。设 \(w=p1^{c1} * p2^{c2} * p3^{c3}\),它对最小公倍数的贡献就是 \(w\),但是如果我把它拆成三个环来处理,使得每个环大小仅包含一种质数,效果是一样的。而且拆了之后,环的大小也变小了,显然答案的排列会更优。

因为我们的构造方式是:对于一个大小为 \(k\) 的环,我们先输出 \(k - 1\) 个顺序为 \(l+1..l+k-1\) 的数,然后再输 \(l\)。其中 \(l\) 为当前可填的最小的数

问题再次转化

现在问题变成:

现在有一堆质数(\(n\) 以内),每个质数的使用次数上限是已知的(就是上面的 \(c\) 的大小上限)。我要选择一些质数(或它的幂),使他们的和 \(\leq n\),然后这些质数(或它的幂)的乘积要最大。

而这其实就是有限背包问题。

设 \(f_{i,j}\) 表示我们处理到第i个质数、当前和为j所能获得的最大秩。则 \(f_{i,j}=\max(f_{i-1,j-w}*w)\)。而我们要求排列的话,只需记录一下每个状态是由哪个状态转移过来的,最后还原即可。

于是我们似乎做完了

嗯,确实是似乎

因为你会发现一堆质数的最小公倍数会灰常灰常大

所以题解给了一个很牛逼的方法

那就是给 \(f\) 值转为自然对数来做。

即 \(f_{i,j} \Longleftrightarrow \ln{f_{i,j}}\)

于是转移时 \(\times w\) 变为 \(+ \ln{w}\)

\(Code\)

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std; const int N = 1e4 + 5;
const double INF = 1e40;
int t , n , vis[N] , tot , pr[1300] , d[1300] , cnt , g[1300][N];
double f[1300][N] , ans; inline void getprime(int Mx)
{
vis[1] = 1;
for(register int i = 2; i <= Mx; i++)
{
if (!vis[i]) pr[++tot] = i;
for(register int j = 1; j <= tot && pr[j] * i <= Mx; j++)
{
vis[pr[j] * i] = 1;
if (i % pr[j] == 0) break;
}
}
} int main()
{
getprime(1e4);
scanf("%d" , &t);
for(; t; t--)
{
scanf("%d" , &n);
memset(f , 0 , sizeof f);
f[0][0] = log(1.0);
for(register int i = 1; i <= tot; i++)
for(register int j = 0; j <= n; j++)
{
f[i][j] = f[i - 1][j];
int w = pr[i];
while (j - w >= 0)
{
if (f[i - 1][j - w] + log(1.0 * w) > f[i][j]) f[i][j] = f[i - 1][j - w] + log(1.0 * w) , g[i][j] = w;
w *= pr[i];
}
}
ans = -INF;
int m , sum = 0;
for(register int i = 0; i <= n; i++)
if (f[tot][i] > ans) ans = f[tot][i] , m = i;
cnt = 0;
for(register int i = tot; i; i--)
{
if (g[i][m]) d[++cnt] = g[i][m] , sum += d[cnt];
m -= g[i][m];
}
while (sum < n) d[++cnt] = 1 , sum++;
sort(d + 1 , d + cnt + 1);
int k = 1;
for(register int i = 1; i <= cnt; i++)
{
for(register int j = 1; j < d[i]; j++)
printf("%d " , k + j);
printf("%d " , k) , k += d[i];
}
printf("\n");
}
}

JZOJ 3232. 【佛山市选2013】排列的更多相关文章

  1. 【佛山市选2013】JZOJ2020年8月7日T4 排列

    [佛山市选2013]JZOJ2020年8月7日T4 排列 题目 描述 一个关于n个元素的排列是指一个从{1, 2, -, n}到{1, 2, -, n}的一一映射的函数.这个排列p的秩是指最小的k,使 ...

  2. 【佛山市选2013】JZOJ2020年8月7日提高组T3 海明距离

    [佛山市选2013]JZOJ2020年8月7日提高组T3 海明距离 题目 描述 对于二进制串a,b,他们之间的海明距离是指两个串异或之后串中1的个数.异或的规则为: 0 XOR 0 = 0 1 XOR ...

  3. 【佛山市选2013】JZOJ2020年8月7日提高组T2 树环转换

    [佛山市选2013]JZOJ2020年8月7日提高组T2 树环转换 题目 描述 给定一棵N个节点的树,去掉这棵树的一条边需要消耗值1,为这个图的两个点加上一条边也需要消耗值1.树的节点编号从1开始.在 ...

  4. 【佛山市选2013】JZOJ2020年8月7日提高组T1 回文子序列

    [佛山市选2013]JZOJ2020年8月7日提高组T1 回文子序列 题目 描述 回文序列是指左右对称的序列.例如1 2 3 2 1是回文序列,但是1 2 3 2 2就不是.我们会给定一个N×M的矩阵 ...

  5. 纪中集训2020.02.05【NOIP提高组】模拟B 组总结反思——【佛山市选2010】组合数计算,生成字符串 PPMM

    目录 JZOJ2290. [佛山市选2010]组合数计算 比赛时 之后 JZOJ2291. [佛山市选2010]生成字符串 比赛时 之后 JZOJ2292. PPMM 比赛时 之后 JZOJ2290. ...

  6. JZOJ 1003 [ 东莞市选 2007 ] 拦截导弹 —— 递推

    题目:https://jzoj.net/senior/#main/show/1003 n^2 的话递推就可以啦. 代码如下: #include<iostream> #include< ...

  7. [JZOJ4024] [佛山市选2015] 石子游戏 解题报告

    Description     Alice 和 Bob 总喜欢聚在一起玩游戏(T_T),今天他(她)们玩的是一款新型的取石子游戏.游戏一开始有N堆石子,Alice 和 Bob 轮流取出石子.在每次操作 ...

  8. 【原创】开源.NET排列组合组件KwCombinatorics使用(二)——排列生成

           本博客所有文章分类的总目录:本博客博文总目录-实时更新 本博客其他.NET开源项目文章目录:[目录]本博客其他.NET开源项目文章目录 KwCombinatorics组件文章目录: 1. ...

  9. 生成n个数的全排列【递归、回溯】

    下面讨论的是n个互不相同的数形成的不同排列的个数.毕竟,假如n个数当中有相同的数,那n!种排列当中肯定会有一些排列是重复的,这样就是一个不一样的问题了. /*===================== ...

  10. xamarin for vs2013

    安装需求(下载的包及版本) 先安装VS2013 然后到官网下Xamarin,运行后会自动下载以下文件 这是下载的详细列表 jdk-6u39-windows-i586.exe(69.73M) Andro ...

随机推荐

  1. 【数据库】SQL-随机生成区间内数值、日期、字符串,mock数据

    〇.概述 1.参考 2.其他 一.随机生成数值 1.随机生成函数random_int() -- 随机数生成函数,int版 CREATE OR REPLACE FUNCTION random_int( ...

  2. go-carbon 1.5.2版本发布, 修复已知 bug 和新增功能及葡萄牙语翻译文件

    carbon 是一个轻量级.语义化.对开发者友好的golang时间处理库,支持链式调用. 目前已被 [awesome-go](https://github.com/avelino/awesome-go ...

  3. 【深入浅出SpringCloud原理及实战】「SpringCloud-Alibaba系列」微服务模式搭建系统基础架构实战指南及版本规划踩坑分析

    Spring Cloud Alibaba Nacos Discovery Spring Boot 应用程序在服务注册与发现方面提供和 Nacos 的无缝集成. 通过一些简单的注解,您可以快速来注册一个 ...

  4. Windows 安装 Zookeeper 详细步骤

    Windows 安装 Zookeeper 详细步骤 一. Zookeeper 安装包下载 1.官网地址 Zookeeper官网 2.安装包下载 这里选择目前的稳定版 3.6.3 下载 可以看到有两个选 ...

  5. python各种小知识

    一.三元表达式 1. 简化步骤1:代码简单且只有一行,可以直接在冒号后面编写 三元表达式: 数据值1+ if 条件+else 数据值2条件成立则使用数据值1,条件不成立则使用数据值2: 当结果是二选一 ...

  6. 更改jenkins插件地址为国内源地址

    1.在插件管理里替换源地址 在这个界面往下拉,可看到URL地址,将其替换为:https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-ce ...

  7. 实现 .Net 7 下的数据库定时检查

    在软件开发过程中,有时候我们需要定时地检查数据库中的数据,并在发现新增数据时触发一个动作.为了实现这个需求,我们在 .Net 7 下进行一次简单的演示. PeriodicTimer .Net 6 中新 ...

  8. echarts去除下载小图标

    toolbox: { show: true, orient: 'vertical', left: 'right', top: 'center', feature: { dataView: { read ...

  9. python 数据迁移

    Python数据库迁移 操作数据库 mysql uroot -p create database Python1031 charset=utf8; 数据迁移 from flask_migrate im ...

  10. 2、postman调试

    Postman接口调试: postman博客参考 Postman是一个API(接口)开发协作平台,其提供了发送请求.检查响应.自动化测试.数据模拟.服务监控.文档分享等一系列与API(接口)开发有关的 ...