码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj 2839 集合计数——二项式反演

时间:2019-01-15 21:03:53      阅读:282      评论:0      收藏:0      [点我收藏+]

标签:for   注意   scan   ons   pre   names   tps   int   name   

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2839

设 \( g(i) \) 表示至少有 i 个, \( f(i) \) 表示恰好有 i 个,则

\( g(i)=C_{n}^{i}*(2^{2^{n-i}}-1) \)

\( g(i)=\sum\limits_{j=i}^{n}C_{j}^{i}f(j) \)

\( f(i)=\sum\limits_{j=i}^{n}(-1)^{j-i}C_{j}^{i}g(j) \)

以为把 g 写出来后 \( C_{n}^{i}*C_{i}^{j} = C_{n}^{j} \) ,然而其实 \( C_{n}^{i}*C_{i}^{j} = C_{n}^{j}*C_{n-j}^{i-j} \) 。

注意指数取模是 mod-1 。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=1e6+5,mod=1e9+7;
int n,k,g[N],jc[N],jcn[N];
void upd(int &x){x>=mod?x-=mod:0;x<0?x+=mod:0;}
int pw(int x,int k,int md=mod)
{int ret=1;while(k){if(k&1)ret=(ll)ret*x%md;x=(ll)x*x%md;k>>=1;}return ret;}
void init()
{
  jc[0]=1;for(int i=1;i<=n;i++)jc[i]=(ll)jc[i-1]*i%mod;
  jcn[n]=pw(jc[n],mod-2);for(int i=n-1;i>=0;i--)jcn[i]=(ll)jcn[i+1]*(i+1)%mod;
}
int C(int n,int m)
{return (ll)jc[n]*jcn[m]%mod*jcn[n-m]%mod;}
int main()
{
  scanf("%d%d",&n,&k);
  init();
  int ans=0;
  for(int i=k,j=1;i<=n;i++,j=-j)
    ans=(ans+(ll)j*C(i,k)*C(n,i)%mod*(pw(2,pw(2,n-i,mod-1))-1))%mod,upd(ans);
  printf("%d\n",ans);
  return 0;
}

 

bzoj 2839 集合计数——二项式反演

标签:for   注意   scan   ons   pre   names   tps   int   name   

原文地址:https://www.cnblogs.com/Narh/p/10274154.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!