• 【ZOJ 3556 How Many Sets I】


    题目链接题目

    大概题意:有一个大集合S,里面有n(≤231-1)个元素,现在从中任意选出k(≤231-1)个子集组成一个有序集合对(S1,S2.....Sk),问其中有多少个集合对满足所有选出的子集的交集为空(S1 ∩ S2 .....Sk = Φ)

    做法

    先说句废话。

    首先要注意的是题目说所有的子集的交集为空集,不代表某两个子集之间交集一定为空。甚至有可能任意两个子集之间交集都不为空,但是所有子集之间的交集为空。

    我当时想到这一点之后,就开始用排除法。即用全部减去不符合要求的。然后开始了漫长的推公式。。。。。。

    推半天推不出来,上网看题解。发现是恶心的容斥原理。。。

     题解一

    (容斥原理不懂的同学可以跳过这一部分)

    首先方案总数为(2^n)^k

    所有子集的交集至少含一个元素的方案C(n,1)*(2^(n-1))^k

    所以答案就是(2^n)^k-C(n,1)*(2^(n-1))^k,哈哈,这题真简单,要什么容斥原理。。。。

    错!!!!!!!!

    我当时也是这么想的,结果发现——————

    交集只含一个元素的方案被减掉了,但是交集只含两个元素的方案被减了两次!

    于是我们加多一项,变成了

    (2^n)^k-C(n,1)*(2^(n-1))^k+C(n,2)*(2^(n-2))^k

    但是仔细再想想,不对,那交集只含三个元素的方案发生了什么。。。

    事实上,交集只含三个元素的方案被减了C(3,1)次,又被加上了C(3,2)次,所以还要减去一次,即变成

    (2^n)^k-C(n,1)*(2^(n-1))^k+C(n,2)*(2^(n-2))^k-C(n,3)*(2^(n-3))

    然后。。。。

    是的,你猜对了,最后这条式子会变成这样的庞然大物:

    (2^n)^k-C(n,1)*(2^(n-1))^k+C(n,2)*(2^(n-2))^k-C(n,3)*(2^(n-3))....

    +(-1)^t*C(n,t)*(2^(n-t))^k........+(-1)^n*C(n,n)*(2^(n-n))^k

    再然后,把这条式看成是类似(a+b)^n展开式的形式,整合得到(2^k-1)^n

    再然后套个快速幂取模就行了。。。

    总结:这种方法还是很有启发性的,除了式子庞大,极费脑力,考试时绝对推不出来就是了

     

     

     

     

    题解二

    在和albertxwz的交流中,我发现了思想的闪光。

    下面无耻的抄袭下他的简洁思想:

    对于大集合每一个元素x,每个子集Si要么包含它,要么不包含它。也就是两种可能。

    所以元素x在所有子集中的情况可以统计出来:2^k

    但是所有子集不能都包含元素x,否则就不符合条件了,所以还要减1:2^k-1

    总共有n个元素,再加上一个乘幂:(2^k-1)^n

    哈哈,这题真简单,要什么容斥原理。。。

     

    代码

     

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <cstdlib>
     4 #include <iostream>
     5 using namespace std;
     6 
     7 const int modnum = 1000000007;
     8 
     9 int n, m;
    10 
    11 int pow_mod(long long a, int x)
    12 {
    13   long long ans = 1;
    14   for (long long i = 1; i <= x; i <<= 1)
    15   {
    16       if (x & i) ans = ans * a % modnum;
    17       a = a * a % modnum;
    18   }
    19   return ans;
    20 }
    21 void doing()
    22 {
    23   printf("%d
    ", pow_mod(pow_mod(2, m) - 1, n));
    24 }
    25 int main()
    26 {
    27   while (scanf("%d%d", &n, &m) == 2) doing();
    28   return 0;
    29 }

     

     

  • 相关阅读:
    Java总结篇系列:Java多线程(一)
    path方法总结
    Ember模板中的操作指向
    EmberJS路由详解
    观察器observes与对象初始化
    emberjs重写补充类之reopen方法和reopenClass方法
    emberjs创建类
    2014Ember带来怎样的变化?
    创建应用和模型和控制器
    自定义指令
  • 原文地址:https://www.cnblogs.com/distaling-7732/p/7452563.html
Copyright © 2020-2023  润新知