12.02 CW 模拟赛 T2.排列

news/2024/12/2 20:51:20/文章来源:https://www.cnblogs.com/YzaCsp/p/18582701

前言

也是找到了韩国原题, 有用!

算法

场上有一个比较显然的想法, 即计算出每种逆序对数量对应多少排列, 从而计算出排名第 \(k\) 小的排列有多少个逆序对

但是即使计算出来了, 我们也不好实现, 分析原因发现, 实际上是因为不好确定应该怎么填数, 时间复杂度仍然趋势

一个显然的想法是, 我们在计算出前 \(i\) 位时, 需要相应的的去找后面的解, 那么思路就比较清晰了

首先, 我们需要计算出每种逆序对数量对应多少排列, 考虑 \(\rm{dp}\) (其实我自己不可能考虑的出来, 没有题解的话思考难度应该到 \(\color{#3498db}{提高+/省选−}\))

这个时候 \(\rm{HYH}\) 大佬正在讲这个题, 疑似可以打表找规律, 不管了

首先, 令 \(f_{i, j}\) 表示 \(i\) 个数的排列, 逆序对个数为 \(j\) 的方案数

我们考虑在 \(i - 1\) 的排列中插入 \(i\) 来递推 \(i\) 的状态, 显然的, 我们把 \(i\) 插入在 \(p \in [0, i - 1]\)\(i\) 个位置时, 逆序对个数都会 \(+ (i - p - 1)\)

那么有转移, 注意判断边界条件

\[f_{i, k} = \sum_{j = k - i + 1}^{k} f_{i - 1, j} \]

时空复杂度都为 \(\mathcal{O} (n \omega)\) , 其中 \(\omega = 200\) , 注意使用前缀和优化, 后面要用 \(i\) 这一维所以不能滚动数组

完事之后考虑推答案,

首先来说, 我们可以考虑从前往后加入数字, 以此来确定第 \(k\) 个全排列
利用先前推出的 \(f\) 数组, 我们可以知道, 每一位产生的逆序对个数, 具体的, 找到最小的逆序对个数 \(j\) , 使得中间经过的逆序对个数严格小于 \(k\)

然后我们就可以知道, 对于从前往后加入的情况, 每次需要制造的逆序对个数

那么我们就可以每次二分插入的数字, 如果制造的逆序对个数 $ < $ 需要制造的逆序对个数, 那么就合法, 并且在这个的基础上尽可能选择更大的数字, 以此得到答案

代码

借用 \(\rm{ZCY}\) 巨佬的代码, 我也确实不太理解

#include <bits/stdc++.h>
using namespace std;
#define int __int128
#define lowbit(x) (x & (-x))
const int N = 1e6 + 5;
int n, fnl[N], s[N];
__int128 sum[300];
__int128 pre[300], k;
vector<vector<__int128>> dp;
__int128 read()
{__int128 x = 0, f = 1;char ch = getchar();while (ch < '0' || ch > '9'){if (ch == '-')f = -1;ch = getchar();}while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}return x * f;
}
int col[N];
void update(int pos, int w)
{for (int i = pos; i <= n; i += lowbit(i))s[i] += w;
}
int query(int pos)
{int res = 0;for (int i = pos; i > 0; i -= lowbit(i))res += s[i];return res;
}
void write(int x)
{if (x >= 10)write(x / 10);putchar(x % 10 + '0');
}
signed main()
{n = read(), k = read();dp.resize(n + 2);int w = 0;if (n <= 21)w = 220;else if (n <= 100)w = 100;elsew = 10;for (int i = 0; i <= n; i++)dp[i].resize(w + 5);dp[0][0] = 1;for (int i = 1; i <= n; i++){pre[0] = dp[i - 1][0];for (int j = 1; j <= w; j++)pre[j] = pre[j - 1] + dp[i - 1][j];for (int j = 0; j < min(i, w); j++)dp[i][j] = pre[j];for (int j = i; j <= w; j++)dp[i][j] = pre[j] - pre[j - i];}int l = 0, r = 0, ans = 0;sum[0] = dp[n][0];for (ans = 0; ans <= w; ans++){if (ans > 0)sum[ans] = sum[ans - 1] + dp[n][ans];if (sum[ans] >= k)break;}if (ans)k -= sum[ans - 1]; // 在逆序对数相同的排列中的排名for (int i = 1; i <= n; i++){int tmp = 0;for (int j = ans; j >= 0; j--){tmp += dp[n - i][j];if (tmp >= k){k -= tmp - dp[n - i][j];col[i] = ans - j + 1; // i 位置上逆序对的个数ans = j;break;}}}for (int i = 1; i <= n; i++)update(i, 1);for (int i = 1; i <= n; i++){int l = 1, r = n, ans = 0;while (l <= r){int mid = (l + r) >> 1;if (query(mid) < col[i])ans = mid, l = mid + 1;elser = mid - 1;}ans++;update(ans, -1);write(ans), putchar(' ');}return 0;
}

总结

递推思想的应用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/845623.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

信息安全概论复习4

数字签字和身份识别报文鉴别(接收方鉴别报文真伪)报文源鉴别(发方鉴别)报文宿鉴别(收方鉴别)报文时间性鉴别(能够挫败重播攻击) 初始向量法(事先约定一组初始向量Zi,Zi作为初始向量链接加密第i份报文Mi,只有对应才能还原,重点在加密)时间参数法(类似时间戳,第i份报文…

【知识】模拟退火

模拟退火算法!模拟退火 概念:温度(步长):初始温度 \(T\)终止温度衰减系数 $ 0 \sim 1$随机选择一个点: \(f(新点) - f(当前点) = \Delta E\)\(\Delta E < 0\) 跳到新点 \(\Delta E>0\) 以一定概率跳过去,概率为 \(e^{- \frac{\Delta E}{T}}\)过程如下图:题型:A…

实验五 C语言指针应用编程

实验五 C语言指针应用编程 实验任务1——数组求最大最小值 #include <stdio.h> #define N 5 void input(int x[], int n); void output(int x[], int n); void find_min_max(int x[], int n, int* pmin, int* pmax); int main() {int a[N];int min, max;printf("录入…

使用Tauri创建桌面应用

当前是在 Windows 环境下 1.准备系统依赖项Microsoft C++ 构建工具WebView2 (Windows10 v1803 以上版本不用下载,已经默认安装了)下载安装 Rust 下载安装 Rust 需要重启终端或者系统重新打开cmd,键入rustc --version,出现 rust 版本号,说明安装成功 2.开始 #npm npm create…

【windows工作合集】 远程连接出现问题记录

问题记录:由于需求要登录本地windows的虚拟机 但是在输入用户信息/密码都正确的情况下出现上面截图的问题 于是就百度进行查阅解决--主要就是说我这边机器可能是因为系统更新或者一些注册表的问题导致信息对不上,所以被认为无法登录 (系统更新。微软系统补丁的更新将 CredSSP…

AGC032 VP记录

A 17:35 +0 B 39:51 +0 C 80:28 +4 A.Limited Insertion 简要题面: 最初有一个空序列,每次操作选定一个 \(i\) 并把 \(i\) 插入到位置 \(i\) ,给定最终序列,构造一种合法方案或者输出 -1 。 \(n \leq 100\) 做法: 简单思考发现每次操作出来的数一定从后往前对应了最终序列…

高级语言程序设计第十次作业

代码写的最长的一题,写了十五分钟,数据类型还写错了使用ftell与fseek的组合来计算字节数,跟上面的一题类似这题因为我没创建相关的文件所以输出是这样,但是创建了之后是可以成功写入的可以将输入内容复制通过c语言程序这个也是复制的一个用法同样通过ftell与fseek来计算字节…

H5-15 H5里面的CSS

1、CSS 简介使用CSS的目的就是让网页具有美观一致的页面 2、CSS概念CSS (Cascading Style Sheets)层叠样式表,又叫级联样式表,简称样式表CSS文件后缀名为 .cssCSS用于HTML文档中元素样式的定义 3、为什么需要CSS使用css的目的就是让网页具有美观一致的页面 4、语法CSS规则由…

实验5 继承和多态

实验任务三 源码1 #pragma once2 #include<iostream>3 #include<string>4 5 using std::string;6 using std::cout;7 using std::endl;8 9 //电子宠物类 10 class MachinePets { 11 private: 12 string nickname; 13 public: 14 MachinePets(const string&…

idea创建web项目并连接数据库

1.在idea中连接数据库在连接的数据库中,可以写SQL语句,创建数据库、表等。 2.我的项目结构---学生请假系统Dao层:写一个学生实体类 Servlet层:业务层具体的怎么实现相关操作 1)最开始加上这个之后就不用配置映射文件了 2)然后是这个就不用另外的建立连接了 3)在resouces…

chrome 替换network中的返回内容,用以跨步调试

在开发调试中,有时候,某个接口,或者文件返回内容有问题,但线上的文件没问题。这时候就可以通过更改network中返回内容来实现跨步调试了。 test.html<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta n…

天梯赛 L2-004 这是二叉搜索树吗? 数据结构

反思:使用指针前先分配内存。#include<bits/stdc++.h> using namespace std; typedef struct node {int data;struct node* left;struct node* right; }*T; queue<int>q1; queue<int>q2; queue<int>q3; T result; void built1(T &t,int x) {if(t=…