康托展开+两道例题

本文介绍了康托展开的概念及其在计算字符串字典序位置和解决八数码难题中的应用。通过优化算法,将复杂度降低到O(nlogn),并展示了如何使用树状数组进行优化。此外,还讨论了康托展开在空间优化上的优势,例如在八数码难题中用于减少状态存储需求。
摘要由CSDN通过智能技术生成

简介

康托展开用于计算某个字符串在所有字典序中的位置。常用于状态压缩和哈希。

公式

一个字符串A1,A2,…,An,假设都是数字0-9
这个字符串在所有字典序中的位置为:

B1*(n-1)!+B2*(n-2)!+...+Bn*(n-n)!
Bn表示这个字符后面比它小的字符的个数
以52134为例,B1=4,因为2134都比5小,B2=1,因为只有12小,...

这么做的理由是后面更小的字符可以换到当前位置上构成更小的字典序,后面的n个字符又有n!种排列方式。

优化

如果每次都要遍历一遍后面的字符,复杂度为O(n2),大部分的题目还是过不了,如果用树状数组进行优化,可以将复杂度降到O(nlogn)级别,可以应对绝大部分的题目。

例题

康托展开-洛谷

//AC代码
#include <bits/stdc++.h>
#define maxn 1000000 + 5
using namespace std;
int n;
long long num[maxn]; //记录输入的数字
long long C[maxn] = {
   0};

inline int lowbit(int x)
{
   
    return x & (-x);
}

inline int presum(int x) //presum(i)表示比i小的数字个数
{
   
    int res = 0;
    while (x > 0)
    {
   
        res += C[x];
        x -= lowbit(x);
    }
    return res;
}

inline void update(int x, int vaule)
{
   
    while (x <= n)
    {
   
        C[x] += vaule;
        x += lowbit(x);
    }
}

int main()
{
   
    long long f = 1, ans = 1;
    scanf("%d", &n);
    for (int i = n; i 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值