zoukankan      html  css  js  c++  java
  • [模板] 康托展开和逆展开

    感谢ZLY告诉我这个知识点

    附上比较不错的模板

    https://www.cnblogs.com/Howe-Young/p/4348777.html

    例题:

    http://nyoj.top/problem/139(康托展开)

    http://nyoj.top/problem/143(康托逆展开)

    此题是理解康托展开非常好的例子

    就该题而言会不会康托展开都会想到用排列组合计算比该序列小的序列有多少个

    我也认为这就是康托展开的原理:

    记录当前序列为该序列字典序中的第N大(等同于映射为整形值),由于其序列唯一性,则可通过序列编号逆运算出原序列。

    由于是自己推的, 不保证正确性,待我再深入学习学习再修改

    typedef long long ll;
    const int MAXN = 1e6 + 10;
    int cnt[MAXN] = {0};
    
    int main()
    {
        int n;
        cin>>n;
    
        while(n--)
        {
            string rs;
    
            cin>>rs;
    
            ll ans = 0;
    
            for(int i = 0; i < rs.length(); i++)
            {
                int rsum = 0;
                for(int j = i + 1; j < rs.length(); j++)
                {
                    if(rs[j] < rs[i])
                        rsum++;
                }
                cnt[i] = rsum;
            }
    
            for(ll i = rs.length() - 2, x = 1, rs = 1; i >= 0; i--, rs++)
            {
                x *= rs;
                ans += (cnt[i] * x);
            }
    
            cout<<ans + 1<<'
    ';
            
        }
    }

    逆展开:

    预处理fac阶乘数组

    从尾部依次除fac[len - i](i from 1 to len) 除数为比该数小的数的个数

    然后n方暴力查找 去掉该数 并修改其后数组数量 -1 动态更新,保证解的唯一性

    用过我直接标-1 减了还减 反正也匹配不上 比较方便 

    
    typedef long long ll;
    
    const int MAXN = 1e3 + 10;
    
    char arr[MAXN] = "abcdefghijkl";
    
    int fac[MAXN] = {1};
    
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);     cout.tie(0);
        //freopen("D://test.in", "r", stdin);
        //freopen("D://test.out", "w", stdout);
    
        for(ll x = 1, y = 1; y < 15;  y++)
        {
            fac[y] = x * y;
            x = x * y;
            //cout<<fac[y]<<' ';
        }
    
        int cnt[20] = {0};
    
        int n;
    
        cin>>n;
    
        while(n--)
        {
            vector <char> ans;
    
            for(int i = 0; i < 12; i++)
            {
                cnt[i] = i;
            }
    
            ll rx;
    
            cin>>rx;
            
            --rx;
    
            for(int i = 11; i >= 0; i--)
            {
                int rcnt = rx / fac[i];
                rx %= fac[i];
    
                for(int j = 0; j < 12; j++)
                {
                    if(cnt[j] == rcnt)
                    {
                        cnt[j] = -1;
    
                        ans.push_back(j + 'a');
                        
                        for(int k = j + 1; k < 12; k++)
                        {
                            --cnt[k];
                        }
                        
                        break;
                    }
                }
            }
            
    
            for(char x : ans)
                cout<<x;
    
    
            cout<<'
    ';
        }
        
        return 0;
    }
    
  • 相关阅读:
    Chrome浏览器与常用插件推荐
    时间戳 转换24小时制
    fis3 开启相对地址
    web手机端禁止滑动,web手机端禁止上下滑动。
    rem的用法
    手机端复制,pc端复制
    ruby 镜像安装
    使用Potree渲染大规模点云-踩坑记录
    移动端真机调试神器-spy-debugger
    手撕Promise.any
  • 原文地址:https://www.cnblogs.com/zeolim/p/12270399.html
Copyright © 2011-2022 走看看