• luogu P5367 【模板】康托展开 / P2518 [HAOI2010]计数


    今天学习康托展开 和 可重集康托展开。。。

    康托展开。。就是给你一个1~n全排列,问它的排名。。

    例如:x1, x2 , x3 , x4 , x5 是一个1~5的全排列,现在我们要求它的排名。。

    从第1位开始枚举。。

    然后枚举j,当然这个j要< xi ,并且不能在x(1~i-1)中出现过。

    发现当 j < xi 时 ,后面无论怎样填,都会比所求排列的字典序小。。所以就是! (len-i) 。累加到答案中。

    枚举完j后,就令第i位为xi,将xi标记上即可,后面枚举 j 时就不能在枚举到 xi了。

    考虑优化枚举 j 这个过程。。

    开个树状数组。记录一下前面1~i-1出现过那些数,合法的j的个数即为xi-1-ask(xi - 1)啦,直接乘上 ! (len-i) 即可。。

    最后add(xi)。。

    然后就是蛤OI的这道计数题啦。。

    只不过是可以有相同的元素罢了。。

    把上面枚举j统计答案乘!(len-i)的过程改为乘上后面剩余元素可重集的全排列即可。。

    其他的大致相同。。这个玩意就不能用树状数组了,只能老老实实枚举 j 。。

    由于这个题它TM不取模,,搞得求可重集的全排列的过程很难搞。。

    虽然最后结果不会爆long long 但中间也可能会爆。。

    所以我们就不能直接按求可重集的全排列的公式来求了。。

    用组合数。。而由于我是个蒟蒻,不会用符号,就没有办法演示了。。看代码吧。。

    计算组合数要用递推预处理,不然还不如直接搞阶乘上下相消呢(比较麻烦)

    P2518计数Code    怎么这么短。。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll long long
    using namespace std;
    char a[100];
    int b[11],len;
    ll ans,c[55][55];
    ll clac(int x){
        ll res=1;
        for(int i=0;i<=9;i++){
            res*=c[x][b[i]];x-=b[i];
        }
        return res;
    }
    int main(){
        scanf("%s",a+1);len=strlen(a+1);
        c[0][0]=1;
        for(int i=1;i<=50;i++){
            c[i][0]=1;
            for(int j=1;j<=i;j++) c[i][j]=c[i-1][j]+c[i-1][j-1];
        }
        for(int i=1;i<=len;i++) b[a[i]-'0']++;
        for(int i=1;i<=len;i++){
            for(int j=0;j<a[i]-'0';j++){
                if(b[j]){
                    b[j]--;
                    ans+=clac(len-i);
                    b[j]++;
                }
            }
            b[a[i]-'0']--;
        }
        printf("%lld
    ",ans);
    }
  • 相关阅读:
    嘀嘀咕 (1)
    碎碎念(4)
    渲染层错误] TypeError: Cannot read property 'replace' of undefined at rewrit
    怎么跳出foreach
    vs code的Go Live不出现
    ES6
    h5分享到微信,分享到朋友圈
    网页之间传值与获取值
    原生js添加节点的高级简便写法
    原型链
  • 原文地址:https://www.cnblogs.com/SyhAKIOI/p/11730862.html
Copyright © 2020-2023  润新知