zoukankan      html  css  js  c++  java
  • bzoj2839 集合计数(容斥+组合)

    集合计数

    内存限制:128 MiB 时间限制:1000 ms 标准输入输出
     
     

    题目描述

    一个有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;

    一道很好的数论题(反正我看题解才做出来的 %%%%*ZJ   https://www.cnblogs.com/zj75211/p/8029343.html) 我有点菜,各种错误。

    思路很奇妙,第一步:首先选出来C(n,k)个数,第二步:然后我们要做的就是让剩余集合交集为空。注意,我们选的剩余集合是除了C以外还选了什么(C上再加这个集合)

    解释一下

    例如 3 1

    假设我们通过第一步选出来的数为A

    而第二步我们选出来 C,B

    那么我们最终选的集合为AB ,AC

    再比如我们第二步选 空集,C

    那么我们最终选出来的集合为 A,AC

    既然如此我们需要求的就是所有满足的情况

    正确性验证被我鸽了。。。。。。

    然后我们要做的就是求出方案

    设f[i]为当前集合至少选出i个数的方案数

    设m为n-i(即剩余个数)

    对于剩余n-i个数可以构成$2^{(n-i)}$个集合

    而对于这些集合每个都可以进行选或不选(即$2{^{2^{(n-i)}}}$)种情况

    而不能都不选(对于选了空集也是一种)

      $f[i]=C(n,i)*(2{^{2^{n-i}}}-1)$

    显然我们算多了,然后我们需要容斥掉容斥系数,首先我们发现在所有f[k+1]中我们都多算了C(k+1,k)次

    例如我们固定了四个数ABCD

    我们在k+1中每种都多算了一次

    ABC    D==ACD     B==ABD     C==BCD      A

    得到对于f[k+1]:-C(k+1,k)

      同理f[k+2]:+C(k+2,k+1)*C(k+1,k)==C(k+2,k)

    依次类推

    得到   

    for(ll i=k;i<=n;i++)
        ans=(C(i,k)*f[i]%p*((i-k)&1?-1:1)+ans)%p;

    实际上就类似于多项容斥

    而且这题因为N<=1000000

    如果算C现算肯定不行,考虑到用多次,打表(阶乘及阶乘逆元),但求逆元带log仍然超时

    所以还要线性求逆元

        ni[n]=meng(jie[n],p-2);
        for(ll i=n-1;i>=1;i--)ni[i]=ni[i+1]*(i+1)%p;

    理解一下逆元实际上就是1/?

    而$1/(n+1)!*(n+1)$其实就是$1/(n)! $就求出来逆元了

     

    两个注意点

    :for(ll i=1;i<=maxn;i++) ermi[i]=2*ermi[i-1]%(p-1);//2^ermi[i]%p!=2^ermi[i]%p调两节课

    :for(ll i=0;i<=n;i++)又一节半课,实在是菜

    :ermi[0]又二十分钟,

    除了第一个是稍微有一点思维的错,别的都是低错。实不应该

    首先关于为什么mod (p-1)而不是mod (p)

    这其实要推出来,首先我们必须知道${2^{2^i mod p}}{!=2^{2^i}{mod p}}$

    怎么办 设${2^i}==(kφ(p)+t)$,则原式就为$(2^{k*φ(p)}*2^t) {mod p}$

    根据欧拉定理

    $2^{φ(p)} mod p$同余于1,${2^i}==kφ(p)+t$t就等于$2^i mod φ(p)$,又φ(质数)==p-1

    故%(p-1)而非%p

    以下依然是本人丑陋的还带着调试的代码

     1 #include<bits/stdc++.h>
     2 #define ll long long
     3 #define A 1100000
     4 #define maxn 1000010
     5 #define p 1000000007
     6 using namespace std;
     7 ll m,n,k,f[A],jie[A],ermi[A],ans,ni[A];
     8 inline ll read()
     9 {
    10     ll f=1,x=0;char c=getchar();
    11     while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
    12     while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    13     return f*x;
    14 }
    15 ll meng(ll x,ll k)
    16 {
    17     ll ans=1;
    18     for(;k;k>>=1,x=x*x%p)
    19         if(k&1)
    20             ans=x%p*ans%p;
    21     return ans;
    22 }
    23 ll C(ll n,ll m)
    24 {
    25     if(m==0) return 1;
    26     if(m>n) return 0;
    27     else return (jie[n]*ni[m]%p*ni[n-m])%p;
    28 }
    29 void init()
    30 {
    31     n=read(),k=read();
    32     m=n-k;
    33     jie[0]=1;ni[0]=1;ermi[0]=1;
    34     for(ll i=1;i<=maxn;i++)    ermi[i]=2*ermi[i-1]%(p-1);//2^ermi[i]%p!=2^ermi[i]%p
    35     for(ll i=1;i<=n;i++)    jie[i]=jie[i-1]*i%p;
    36     ni[n]=meng(jie[n],p-2);
    37     for(ll i=n-1;i>=1;i--)ni[i]=ni[i+1]*(i+1)%p;
    38     for(ll i=0;i<=n;i++)    f[i]=C(n,i)%p*(meng(2,ermi[n-i])%p-1)%p;
    39 }
    40 int main()
    41 {
    42 //    freopen("test.in","r",stdin);freopen("vio.out","w",stdout);
    43     ans=0;
    44     init();
    45     for(ll i=k;i<=n;i++)
    46     ans=(C(i,k)*f[i]%p*((i-k)&1?-1:1)+ans)%p;
    47     cout<<(ans%p+p)%p<<endl;
    48 }
    View Code

    以及对拍

     1 #include<bits/stdc++.h>
     2 int main() 
     3 {
     4     while(true) 
     5     {
     6         system("./mkd"),puts("mkd runs out");
     7         system("./std"),puts("std runs out");
     8         system("./vio"),puts("vio runs out");
     9         if(system("diff std.out vio.out")) while(true);
    10         puts("");
    11     }
    12     return 0;
    13 }
    View Code

    嗯,完了

    我已没有下降的余地
  • 相关阅读:
    第一个dubbo程序
    spring aop通过注解实现日志记录
    Java操作zookeeper
    VMware安装Linux并配置网络通信
    多线程工具之CompletionService
    Netty实现简易http_server
    python3.4 + Django1.7.7 表单的一些问题
    【编程练习】八大排序算法
    OpenCV特征点检测------Surf(特征点篇)
    Opencv学习笔记------Harris角点检测
  • 原文地址:https://www.cnblogs.com/znsbc-13/p/11131680.html
Copyright © 2011-2022 走看看