zoukankan      html  css  js  c++  java
  • Bzoj 2839 集合计数 题解

    2839: 集合计数

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 495  Solved: 271
    [Submit][Status][Discuss]

    Description

    一个有N个元素的集合有2^N个不同子集(包含空集),现在要在这2^N个集合中取出若干集合(至少一个),使得
    它们的交集的元素个数为K,求取法的方案数,答案模1000000007。(是质数喔~)

    Input

    一行两个整数N,K

    Output

    一行为答案。

    Sample Input

    3 2

    Sample Output

    6

    HINT

    【样例说明】

    假设原集合为{A,B,C}

    则满足条件的方案为:{AB,ABC},{AC,ABC},{BC,ABC},{AB},{AC},{BC}

    【数据说明】

         对于100%的数据,1≤N≤1000000;0≤K≤N;

      一开始想到的状态数组是f[i],代表我们取交集共选了i个数,但是转移还要去枚举有几个集合,好像挺不靠谱的……
      一看正解,连状态数组都不用,让我想到了10.9考试 第一题建造城市的打法。
      我们同样,先从n个数里提前选出k个数,然后去枚举多出来的集合的交集至少是多少,仍然奇减偶加,假设我们当前要求的是交集多出至少为x的方案数,那么就是:
        (2^(2^(n-k-x))-1)*C(n-k,x)。
      在(2^(2^(n-k-x))-1)即表示在除去k+x个数后的2^(n-k-x)集合中选集合的方案数,由于我们不能一个都不选,所以还得减去全部不选的情况。C(n-k,x)就是在剩下n-k个数中选出x个数的方案数,最后在将总和乘以在n个数中选k个数的方案数。
     1 #include <iostream>
     2 #include <cstdlib>
     3 #include <cstdio>
     4 #include <cstring>
     5 #include <queue>
     6 #include <algorithm>
     7 #include <cmath>
     8 #include <map>
     9 #define N 1000005
    10 using namespace std;
    11 int n,k,p=1000000007;
    12 long long jc[N],ni[N],xp[N];
    13 long long ksm(long long x,long long z)
    14 {
    15     long long ans=1;
    16     while(z>0)
    17     {
    18         if(z&1)
    19         {
    20             ans*=x;
    21             ans%=p;
    22         }   
    23         x*=x;x%=p;
    24         z>>=1;
    25     }   
    26     return ans;
    27 }
    28 int main()
    29 {
    30     scanf("%d%d",&n,&k);
    31     jc[0]=1;xp[0]=1;
    32     for(int i=1;i<=n;i++)
    33     {
    34         jc[i]=(jc[i-1]*i)%p;
    35         xp[i]=(xp[i-1]*2)%p;
    36     }
    37     ni[n]=ksm(jc[n],p-2);
    38     for(int i=n-1;i>=1;i--)ni[i]=(ni[i+1]*(i+1))%p;
    39     ni[0]=1;long long now=2;
    40     long long ans=0;
    41     for(int i=n-k;i>=0;i--)
    42     {
    43         long long tmp=((((now-1)*jc[n-k]%p)*ni[i]%p)*ni[n-k-i])%p;
    44         if(i&1)ans=(ans-tmp+p)%p;
    45         else
    46         {
    47             ans+=tmp;
    48             ans%=p;
    49         }
    50         now*=now;
    51         now%=p;
    52     }
    53     ans*=((jc[n]*ni[k])%p*ni[n-k])%p;
    54     ans%=p;
    55     printf("%lld
    ",ans);
    56     return 0;
    57 }
    View Code
  • 相关阅读:
    大写的服,看完这篇你还不懂RocketMQ算我输
    写一个通用的幂等组件,我觉得很有必要
    如何将分布式锁封装的更优雅
    哇,ElasticSearch多字段权重排序居然可以这么玩
    每日一道 LeetCode (52):三数之和
    JVM 第六篇:极致优化 IDEA 启动速度
    JVM 第五篇:命令行 JVM 故障处理工具
    JVM 第四篇:可视化 JVM 故障处理工具
    JVM 第三篇:Java 类加载机制
    JVM 第二篇:垃圾收集器以及算法
  • 原文地址:https://www.cnblogs.com/liutianrui/p/7678901.html
Copyright © 2011-2022 走看看