zoukankan      html  css  js  c++  java
  • 组合数学练习题(一)——Chemist

     

    题意:

    从 n 个人中选出不超过 k 个人,再在选出的人中选出一些人成为队员,再在队员中选一名队长,求不同的方案数。答案 mod 8388608。

    共有T组询问,每次给你n和k。T ≤ 10^4 k ≤ n ≤ 10^5。

    分析:

    在n个人中选不超过k个人,即可以选择1,2,3...k个人,对于每种情况需要分别计算答案。(C(m,n)表示在n个人中选择m个数的方案数)设选i个人,那么共有C(i,n)种方案,对于每一种方案,在选择的i个人中再选择j名队员,有C(j,i)种方案,对于选择的j名队员,从中再选择一名队长共有C(1,j)=j种方案。根据乘法原理,在n人中选择i人再选择j名队员再选择1名队长的方案数为C(i,n)C(j,i)j。所以我们枚举i,j,再将所有的答案累加就是最终的方案数。

    ans=∑(i:1~k)C(i,n)∑(j:1~i)C(j,i)j

    但是这种做法的时间复杂度为O(T*k^2)=O(TLE)。那么我们让n个人中选择i个人的做法不变,考虑后面的做法,原做法是先选队员再选队长,我们可以考虑先选队长,共有C(1,i)=i种方案,然后对于剩下的i-1个人,他们既可以当队员又可以不当队员,每个人有两种可能,共有2^(i-1)种情况,优化后的答案为:

    ans=∑(i:1~k)C(i,n)i2^(i-1)

    2^(i-1)可以用快速幂计算,优化后的时间复杂度为O(Tklogk)还是会超时。那么怎么办呢???

    看题!

    要mod的数是偶数是不是很奇怪啊,仔细打量我们可以发现,8388608=2^23。而且我们的答案中也有2^(i-1)这种形式,那么当i-1>=23时就不需要计算了,因为mod完的数都为0,对答案没有贡献。这样我们就把复杂度进一步降到了O(T*min(k,23)),是不是非常小啊

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int mod=(1<<23),M=1e5+10;
    int T,n,k;
    ll c[M][26];
    void prework()
    {
        for(int i=0;i<=M;i++)
         c[i][0]=1;
        for(int i=1;i<=M;i++)
         for(int j=1;j<=25;j++)
          c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
    }
    int main()
    {
        prework();
        scanf("%d",&T);
        for(int j=1;j<=T;j++)
        {
            ll ans=0;
            scanf("%d%d",&n,&k);
            for(ll i=1;i<=min(k,24);i++)
            {
                ans+=(i*(1<<(i-1)))%mod*c[n][i];
                ans%=mod;
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }

  • 相关阅读:
    收集 关于php的博文
    hdwiki中插件开发指南
    MySQL中“”的坑
    SpringBoot生成验证码
    Spring中的循环依赖问题
    深入理解AQS(抽象队列同步器)
    JUC下线程的三种等待唤醒机制
    关于List集合的去重
    MySQL:去除 字符串
    MySQL:Can't connect to MySQL server on 'localhost'(10061)
  • 原文地址:https://www.cnblogs.com/nopartyfoucaodong/p/9374020.html
Copyright © 2011-2022 走看看