• BZOJ 2982 combination 脑子+组合数学


    可以发现,整个数列构成一个树形结构,并且是个完全二叉堆(小根堆)。

    并且这个堆的形态在给定$n$后是固定的,第1个位置上显然只能放1。

    对子树的根来说,他自己是所分得的数集中最小的那个,所以从剩下$sz[i]-1$个数字中,挑一些填满左子树的节点,剩下填右子树,相当于继续向下分配数集,由于只有数字的个数影响结果,所以子问题可以递归求解。

    所以有$f[i]=f[i<<1]*f[i<<1|1]*C(sz[i]-1,sz[i<<1])$,其中$f[i]$表示以$i$为根的子树的方案数,$sz[i]$表示以$i$为根的子树的大小,$C(sz[i]-1,sz[i<<1])$表示从$sz[i]-1$中任取了$sz[i<<1]$个;

    #include<cstdio>
    #include<iostream>
    #define R register int
    const int M=10007;
    using namespace std;
    char B[1<<15],*S=B,*T=B;
    #define getchar() (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin))?EOF:*S++)
    inline int g() {
        R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix;
        do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix;
    } int t,n,m,fac[M],Inv[M];
    inline int C(int n,int m) {
        if(n<m) return 0; return fac[n%M]*Inv[fac[m%M]]%M*Inv[fac[(n-m)%M]]%M;
    }
    inline int L(int n,int m) {
        if(n<m) return 0; if(!n) return 1;
        return L(n/M,m/M)*C(n%M,m%M)%M;
    }
    signed main() { 
        t=g(); fac[0]=fac[1]=1; Inv[1]=1; 
        for(R i=2;i<M;++i) fac[i]=fac[i-1]*i%M; for(R i=2;i<M;++i) Inv[i]=(M-M/i*Inv[M%i]%M)%M; 
        while(t--) {n=g(),m=g(); printf("%d
    ",L(n,m));}
    }

    2019.06.02

  • 相关阅读:
    Python函数式编程(一):高级函数
    Python高级特性:列表生成式
    Python高级特性:迭代
    Python高级特性:切片
    Python学习笔记
    关于相机拍照获取图片onActivityResult返回data 为null的问题
    191019
    状语和状语从句
    191018
    191017
  • 原文地址:https://www.cnblogs.com/Jackpei/p/10964736.html
Copyright © 2020-2023  润新知