zoukankan      html  css  js  c++  java
  • [CF1443E] Long Permutation

    [CF1443E] Long Permutation - 康托展开

    Description

    你需要维护一个长度为(n)的排列(P)(初态下为 1,2,3...)和(2)种操作:

    • (1 l r) 求出(sum_{i=l}^r P_i)
    • (2 x)(P)替换为(P)的下(x)个排列

    排列(P)初始为([1,2,3,cdots n])
    总共有(q)次操作

    数据范围:
    (n,qleq2 imes 10^5,xleq 10^5)

    Solution

    显然会动的只有最后的不超过 15 个数,我们用康托展开和逆康托展开暴力处理即可

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    
    int fac[20];
    
    int Cantor(vector<int> &a, int n)
    {
        int ans = 0;
        for (int i = 1; i <= n; i++)
        {
            int tmp = 0;
            for (int j = i + 1; j <= n; j++)
                if (a[j] < a[i])
                    ++tmp;
            ans += tmp * fac[n - i];
        }
        return ans;
    }
    
    vector<int> ICantor(int x, int n)
    {
        vector<int> ans(n + 2), a(n + 2), vec;
        for (int i = 1; i <= n; i++)
            vec.push_back(i);
        for (int i = 1; i <= n; i++)
        {
            a[i] = x / fac[n - i];
            x %= fac[n - i];
        }
        for (int i = 1; i <= n; i++)
        {
            ans[i] = vec[a[i]];
            vec.erase(vec.begin() + a[i]);
        }
        return ans;
    }
    
    struct Solver
    {
        int n;
        vector<int> a;
    
        Solver(int n) : n(n)
        {
            a.resize(n + 2);
            for (int i = 1; i <= n; i++)
                a[i] = i;
        }
    
        void Add(int x)
        {
            int t = Cantor(a, n);
            t += x;
            a = ICantor(t, n);
        }
    
        int Sum(int l, int r)
        {
            int ans = 0;
            for (int i = l; i <= r; i++)
                ans += a[i];
            return ans;
        }
    };
    
    signed main()
    {
        fac[0] = 1;
        for (int i = 1; i <= 16; i++)
            fac[i] = fac[i - 1] * i;
    
        int n, m;
        cin >> n >> m;
        Solver solver(min(n, 15ll));
        for (int i = 1; i <= m; i++)
        {
            int type;
            cin >> type;
            if (type == 1)
            {
                int ans = 0;
                int l, r;
                cin >> l >> r;
                if (n <= 15)
                {
                    ans = solver.Sum(l, r);
                }
                else
                {
                    int ll = n - 15 + 1, rr = n;
                    ll = max(ll, l);
                    rr = min(rr, r);
                    if (ll > rr)
                        ans = (l + r) * (r - l + 1) / 2;
                    if (ll <= rr)
                    {
                        r = min(r, n - 15);
                        if (l <= r)
                            ans = (l + r) * (r - l + 1) / 2;
                    }
                    if (ll <= rr)
                        ans += (rr - ll + 1) * (n - 15);
                    if (ll <= rr)
                        ans += solver.Sum(ll - (n - 15), rr - (n - 15));
                }
                cout << ans << endl;
            }
            else
            {
                int x;
                cin >> x;
                solver.Add(x);
            }
        }
    }
    
  • 相关阅读:
    开放6379端口
    synchronized 实现同步的基础
    pythoning—— 5:实战篇(购物车)
    pythoning ——3、数据类型(字符串)
    pythoning ——2、数据类型(元组、序列)
    pythoning ——1、基础篇
    暗链/黑链
    什么是webshell
    获取当前设备IP
    生成公钥
  • 原文地址:https://www.cnblogs.com/mollnn/p/14557716.html
Copyright © 2011-2022 走看看