[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; }
题目描述
输入格式
输出格式
样例
数据范围与提示
题解
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\n",ans); 48 }
愿你在迷茫时,记起自己的珍贵。