• [BZOJ2839]集合计数


    [组合数学T3]


    数学知识

    update:扩展欧拉定理:

    似乎没什么知识性的东西

     线性求逆元      inv[i]=(mod-mod/i)*inv[mod%i]%mod;    (inv[0]=inv[1]=1)

    预处理逆元,阶乘,逆元的阶乘

        inv[0]=inv[1]=1;
    	fac[1]=1;
    	invfac[0]=invfac[1]=1;
    	for(int i=2;i<=n;i++)
    	{
    		fac[i]=fac[i-1]*i%mod;
    		inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    		invfac[i]=invfac[i-1]*inv[i]%mod;
    	}

    题目描述

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

    输入格式

    一行两个整数N,K

    输出格式

    一行为答案。

    样例

    样例输入

    3 2

    样例输出

    6

    数据范围与提示

    样例说明

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

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

    数据说明

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


    题解

    1.交集为k的方案数==在剩下的n-k个元素中交集为空集的方案数

    2.定义F[i]为交集至少为i的方案数

        则在剩下n-i个元素中,有2^(n-i)个交集

        将这些交集看成新元素,有22n-i种方案,然后减去空集的一种情况

           可得 F[i]=C(n-i,i)*(22n-i -1)

    3.n-=k后  此时求交集为0的方案数,

        根据容斥(事实上容斥并不好想,完全可以打表找规律)

               所求为F0-F1+F2-F3······

    4.又因为n中选k个数有C(n+k,k)个方案

        最后输出*C(n+k,k)

     1 #include<iostream>
     2 #include<cstdio>
     3 #define int long long
     4 using namespace std;
     5 
     6 const int mod=1e9+7;
     7 const int maxn=1000005;
     8 int n,k;
     9 int inv[maxn],fac[maxn],invfac[maxn];
    10 int C(int a,int b)
    11 {
    12     return fac[a]*invfac[b]%mod*invfac[a-b]%mod;
    13 }
    14 int poww(int a,int b,int p)
    15 {
    16     int ans=1;
    17     a%=p;
    18     while(b)
    19     {
    20         if(b&1)  ans=ans*a%p;
    21         b>>=1;
    22         a=a*a%p;
    23     }
    24     ans%=p;
    25     return ans;
    26 }
    27 signed main()
    28 {
    29     scanf("%lld%lld",&n,&k);
    30     inv[0]=inv[1]=1;
    31     fac[1]=1;
    32     invfac[0]=invfac[1]=1;
    33     for(int i=2;i<=n;i++)
    34     {
    35         fac[i]=fac[i-1]*i%mod;
    36         inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    37         invfac[i]=invfac[i-1]*inv[i]%mod;
    38     }
    39     int ans=0;
    40     n-=k;
    41     for(int i=0;i<=n;i++)
    42     {
    43         if(i&1)  ans=(ans-(poww(2,poww(2,n-i,mod-1),mod)-1)*C(n,i))%mod;
    44         else     ans=(ans+(poww(2,poww(2,n-i,mod-1),mod)-1)*C(n,i))%mod;
    45     }
    46     ans=(ans*C(n+k,k)%mod+mod)%mod;
    47     printf("%lld
    ",ans);
    48 }
    View Code
    愿你在迷茫时,记起自己的珍贵。
  • 相关阅读:
    jQuery获取Select选择的Text和 Value(转)
    android学习---EditText
    android学习---Activity
    android学习---LinearLayout
    android学习---布局Layout
    android颜色码制表
    java面试题二
    java面试题一
    基本排序算法java实现
    Integer与int的区别
  • 原文地址:https://www.cnblogs.com/casun547/p/11119405.html
Copyright © 2020-2023  润新知