zoj 3556 How Many Sets I 解题报告 <容斥原理>

链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3556

  容斥原理:个数为n的集合子集个数为2^n。

 从子集中选k个的有序组合个数(子集可重复被选中)有 (2^n)^k=2^(n*k);

  故总数为S=2^(n*k);

  设S(x)为k个集合的有序组合的个数,这些集合都包含至少一个x。

 S(x1&x2)为k个集合的有序组合的个数,这些集合都包含至少一个x1和x2

  S(x1&x2&x3...xk)为k个集合的有序组合的个数,这些集合都包含至少一个x1,x2...xk。

 而  S(x)=(2^(n-1))^k =2^((n-1)*k);

 S(x1&x2)=(2^(n-2))^k=2^((n-2)*k);

 S(x1&x2&...&xi)=(2^(n-i))^k=2^((n-i)*k);

 由容斥原理知,我们要得到的就是

 S-(n,1)*S(x) + (n,2)*(S(x1&x2)-(n,3)*(S(x1&x2&x3)+....(-1)^i*(n,i)*S(x1&x2&...xi)...(-1)^n*(n,n)*S(x1&x2...&xn);

化简得ans=(2^K-1)^N;

 

 1 #include <stdio.h>
2 #include <math.h>
3 typedef long long ll;
4 const ll P=1000000007;
5 ll ksm( ll a, ll b )
6 {
7 ll t=1;
8 if( b==1 )
9 return a;
10 if( b==2 )
11 return (a*a)%P;
12 while( b>0 )
13 {
14 if( b&1 )
15 {
16 t*=a, t%=P;
17 b--;
18 }
19 else
20 {
21 a*=a;
22 a%=P;
23 b/=2;
24 }
25 }
26 return t;
27 }
28 int main( )
29 {
30 ll N, K;
31 while( scanf( "%lld%lld", &N, &K ) != EOF )
32 {
33 ll m=ksm( 2, K );
34 m--;
35 ll ans=ksm( m, N );
36 printf( "%lld\n", ans );
37 }
38 return 0;
39 }

 

你可能感兴趣的:(set)