康托展开和逆康托展开

康托展开

cpp 复制代码
//康托展开
constexpr int M = 998244353;
template<class T>
struct Fenwick {
    //比如说数组长度为5
    //-----------------a[3]
    //------a[1]
    //--a[0]    --a[3]     --a[4]
    //    1    2    3    4    5
    //add(x)修改的是x+1
    //sum(x)查询的是x
    int n;
    std::vector<T>a;
    Fenwick(int n_=0) {
        init(n_);
    }
    void init(int n_) {
        n = n_;
        a.assign(n, T{});
    }
    void add(int x, const T& v) {

        for (int i = x + 1; i <= n; i += i & -i) {
            a[i - 1] = a[i - 1] + v;
        }
    }
    T sum(int x) {
        T ans{};
        
        for (int i = x; i > 0; i -= i & -i) {
            ans = ans + a[i - 1];
        }
        return ans;
    }
    T rangeSum(int l, int r) {
        return sum(r) - sum(l);
    }
};

struct cantor {
    int n;
    std::vector<ll>fac;
    Fenwick<ll> f;
    cantor(int n_) {
        init(n_);
    }
    void init(int n_) {
        n = n_;
        fac.assign(n, 0);
        f.init(n);
        fac[0] = 1;
        for (int i = 1; i < n; i++) {
            fac[i] = i*fac[i - 1] % M;
        }
        for (int i = 0; i < n; i++) {
            f.add(i, 1);
        }
    }
    ll query(int x, std::vector<ll>a) {
        //树状数组求逆序对不就是
        ll sum = 0;
        for (int i = 0; i < x; i++) {
            sum = (sum + fac[n - i - 1] * f.sum(a[i]-1) % M) % M;
            f.add(a[i] - 1, -1);
        }
        return (sum+1) % M;
    }
};

void solve() {
    int n;
    std::cin >> n;
    cantor c(n);
    std::vector<ll>a(n);
    for (int i = 0; i < n; i++) {
        std::cin >> a[i];

    }
    std::cout << c.query(n, a) << "\n";
}

逆康托展开

cpp 复制代码
std::string invcantor(int n, ll k) {
    // 计算阶乘
    std::vector<ll> fac(n, 1);
    for (int i = 1; i < n; i++) {
        fac[i] = fac[i - 1] * i;
    }

    // 初始化未使用的数字集合
    std::vector<int> vis(n);
    std::iota(vis.begin(), vis.end(), 1);

    // 调整 k 为从 0 开始的索引
    k--;

    std::string ans;
    for (int i = 0; i < n; i++) {
        ll fact = fac[n - i - 1];
        int pos = k / fact; // 当前位数字的索引
        ans.push_back(vis[pos]+'0');
        vis.erase(vis.begin() + pos); // 从集合中移除已选数字
        k %= fact; // 更新 k
    }

    return ans;
}
相关推荐
罗西的思考33 分钟前
机器人模型(WM / WAM / VLA)综合分析与对比:从「看」到「想」再到「做」
人工智能·算法·机器学习
Logic1011 小时前
C语言/数据动态规划题解:翻转一次子数组后的最大子数组和——四状态DP(O(n)时间O(1)空间)
c语言·数据结构·动态规划·时间复杂度·算法题·状态机dp·最大子数组和
小哈里2 小时前
【知识】从学科到实践:自然・工程・社科・人文|算法・研发・产品・品牌设计
程序人生·算法·产品·设计·工程
小π军2 小时前
最大重叠区间数量
数据结构·算法
镜像视界(浙江)科技有限公司3 小时前
《视频孪生之上:二维展示终结,三维空间计算重构城市逻辑》——跨摄像连续表达 × 三角测量厘米级定位 × 动态轨迹建模,构建新一代城市空间
大数据·人工智能·算法·矩阵·音视频·空间计算
a187927218313 小时前
【算法】双指针与滑动窗口(二):滑动窗口——吃进、判定、吐出
算法·leetcode·双指针·滑动窗口·原理·模板·算法讲解
铭哥的编程日记3 小时前
从一道 LeetCode Hard 到吃透一类题:加权区间调度「排序 + 二分 + DP」
算法·leetcode·职场和发展
Logic1013 小时前
C语言/数据结构字符串题解:找出DNA序列中未配对的独特序列——排序+遍历(O(nlogn))
c语言·数据结构·字符串·数组·排序·时间复杂度·算法题
Navigator_Z4 小时前
LeetCode //C - 1248. Count Number of Nice Subarrays
c语言·算法·leetcode
wzdark4 小时前
基于链表的内存池设计与内存复用机制4
java·数据结构·链表