组合数学练习题——Chemist

Posted nopartyfoucaodong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了组合数学练习题——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;
}

以上是关于组合数学练习题——Chemist的主要内容,如果未能解决你的问题,请参考以下文章

拓扑排序复习——Chemist

莫比乌斯反演总结——Chemist

Relay.js 没有正确解析组合片段

Python练习册 第 0013 题: 用 Python 写一个爬图片的程序,爬 这个链接里的日本妹子图片 :-),(http://tieba.baidu.com/p/2166231880)(代码片段

JavaScript 代码片段

spring练习,在Eclipse搭建的Spring开发环境中,使用set注入方式,实现对象的依赖关系,通过ClassPathXmlApplicationContext实体类获取Bean对象(代码片段