首页 > 其他分享 >12.02 CW 模拟赛 T2.排列

12.02 CW 模拟赛 T2.排列

时间:2024-12-02 20:54:14浏览次数:7  
标签:ch int T2 个数 12.02 ans CW dp 逆序

前言

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

算法

场上有一个比较显然的想法, 即计算出每种逆序对数量对应多少排列, 从而计算出排名第 \(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;
    else
        w = 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;
            else
                r = mid - 1;
        }
        ans++;
        update(ans, -1);
        write(ans), putchar(' ');
    }
    return 0;
}

总结

递推思想的应用

标签:ch,int,T2,个数,12.02,ans,CW,dp,逆序
From: https://www.cnblogs.com/YzaCsp/p/18582701

相关文章

  • 12.2 CW 模拟赛 赛时记录
    前言\(12\)月的第一场,没有大样例这次带了耳塞,注意考试方法其实并不复杂,先看题吧带上耳塞,终于舒服了看题\(\rm{T1}\)结论题?\(\rm{T2}\)\(\rm{HS}\)似乎讲过???但是我忘了,一会看能不能推一下多半是找规律\(\rm{T3}\)性质题?\(\rm{T4}\)数据结构维护吧,......
  • fatal: 无法访问 ‘https://github.com/moveit/moveit2_tutorials.git/‘:Failed to co
    github在网页可以访问命令行访问就报错,排除网络问题正克隆到'moveit2_tutorials'...fatal:无法访问'https://github.com/moveit/moveit2_tutorials/&#39;:Failedtoconnecttogithub.comport443after44ms:Couldn'tconnecttoserver报错如上,没有登陆github,网......
  • P11218 【MX-S4-T2】「yyOI R2」youyou 不喜欢夏天
    ProblemSolve先不看yy,我们能够发现这个youyou可以贪心,即:某一列全是1,全选,有一个1,尽量只选1(因为可能和上一列的选择连不起来,要衔接),全0,尽量不要选再回来看yy,通过题意以及样例等数据来看,我们能够发现这个yy肯定只会对满足这样的列进行操作:上下两行只选了一行1,另一行是0通过......
  • 德普微一级代理 DP2281 SOT23-6 离线式电流模式 PWM控制器
    ......
  • 德普微 DP8205 SOT23-6 Dual N-Channel Enhancement Power MOSFET
    ......
  • Loadrunner 12.02录制失败,loadrunner no correlation...解决办法
    记录安装Loadrunner12.02后,首次录制失败,提示: 网上查找了:取消自动关联、浏览器设置等,均不生效解决方案:1.确保浏览器可用,啥浏览器都行,只要能用 2.点击recordingoptions 3.General-recording,选择URL-basedscript 4.!!!!HTTPProperties-Supportcharset选择U......
  • 铠侠CD8系列产品对比 KCD81PUG3T20 KCD81PJE3T20 KCD81VUG3T20
    以3200GB容量为例,我们来看一下三个系列的具体差别接口差异:CD8-V系列为PCIe4.0、NVMe™1.4规范兼容,随机读取速度高达1,250KIOPS、随机写入340KIOPS,顺序读取72,00MB/sCD8P-V系列为PCIe® 5.0,NVMe™2.0,随机读取速度高达1,900KIOPS、随机写入400KIOPS,顺序读取12,0......
  • 【产品方案】基于CW32L010低成本电动工具方案
    本方案采用武汉芯源的CW32L010F8P6作为主控实现低成本电动工具方案,通过PWM方波控制算法进行电机转速控制,内部高精度AD转换实现电机电压、反电动势、电流等信号的采样,并实时进行故障停机保护等功能。一、CW32L010单片机特点内核:ARM®Cortex®-M0+:最高主频48MHz●工作......
  • 【产品方案】CW32L010低成本工业仪表
    一、引言先看看L010家族产品功能:TSSOP20的封装可以产品PCB面积极大缩小。以下几个特性让CW32L010在工业仪表上应用更有优势:1.集成了主频高达48MHz的ARM®Cortex®-M0+内核。2.64K超大Flash存储容量。3.极限超低功耗0.3uA,85℃高温漏电仅1.2uA。4.全面升级的低功......
  • 【产品方案】基于CW32L010的低成本USB充电检测仪产品方案
    实物展示LCD版数码管版模块正面模块反面一、引言在当今智能设备时代,USB充电技术普及,高效的USB充电检测仪对设备运行和寿命至关重要。本文介绍一款基于CW32L010F8U6芯片的USB充电检测仪。该检测仪设计为数码管版和LCD版同板,因显示引脚共用,故实际使用时需二选......