首页 > 其他 > 详细

ZROI#999

时间:2019-09-08 16:22:32      阅读:124      评论:0      收藏:0      [点我收藏+]

ZROI#999
很有趣的一道题.本来我是想考虑枚举选几个盒子,但我发现这样并没有对问题有任何简化.
然后就考虑容斥嘛...发现,这个容斥比较简单.
假如令\(f(S)\)\(S\)集合中的玩具不能选的方案数.
那么答案就是:
\[\sum_{s\subseteq T}{(-1)^{|S|}f(S)}\]
那么\(f(S)\)是啥呢?就是\(2^{n-|S|}\).
然后直接套入就好.
怎么理解呢?
考虑容斥的基本形式:
答案=总方案数-不满足一个限制的方案数+不满足两个限制的方案数-不满足三个限制的方案数...
这不就是这个式子嘛....于是愉快\(50pts\).
至于\(n\)高达\(10^6\)的时候,则需要使用\(FMT\)(即高维前缀和)来处理.
等我学会了再来丢人...
\(Code:\)

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <queue>
#include <cmath>
#include <ctime>
#include <map>
#include <set>
#define MEM(x,y) memset ( x , y , sizeof ( x ) )
#define rep(i,a,b) for (int i = a ; i <= b ; ++ i)
#define per(i,a,b) for (int i = a ; i >= b ; -- i)
#define pii pair < int , int >
#define X first
#define Y second
#define rint read<int>
#define int long long
#define pb push_back

using std::set ;
using std::pair ;
using std::max ;
using std::min ;
using std::priority_queue ;
using std::vector ;
using std::swap ;
using std::sort ;
using std::unique ;
using std::greater ;

template < class T >
    inline T read () {
        T x = 0 , f = 1 ; char ch = getchar () ;
        while ( ch < '0' || ch > '9' ) {
            if ( ch == '-' ) f = - 1 ;
            ch = getchar () ;
        }
       while ( ch >= '0' && ch <= '9' ) {
            x = ( x << 3 ) + ( x << 1 ) + ( ch - 48 ) ;
            ch = getchar () ;
       }
   return f * x ;
}

const int N = 1e6 + 100 ;
const int mod = 1e9 + 7 ;

int n , m , tmp[N] , cnt , num , ans ;
bool box[N][25] ;

inline int quick (int a , int p) {
    int res = 1 ;
    while ( p ) {
        if ( p & 1 ) res = ( res * a ) % mod ;
        a = ( a * a ) % mod ; p >>= 1 ;
    }
    return res ;
}

signed main (int argc , char * argv[]) {
    n = rint () ; m = rint () ; int maxsize = 1 << m ; rep ( i , 1 , n )
    { int k = rint () ; rep ( j , 1 , k ) { int x = rint () ; box[i][x] = true ; } }
    for (int i = 0 ; i < maxsize ; ++ i) {
        cnt = 0 ; num = 0 ;
        for (int j = 0 ; j < m ; ++ j)
            if ( i & ( 1 << j ) )
                tmp[++cnt] = j + 1 ;
        rep ( j , 1 , n ) {
            bool f = true ;
            rep ( k , 1 , cnt ) if ( box[j][tmp[k]] ) f = false ;
            if ( f ) ++ num ;
        }
        int d = ( cnt & 1 ) ? - 1 : 1 ;
        ans = ( ans + d * quick ( 2 , num ) % mod ) % mod ;
    }
    printf ("%lld\n" , ( ans % mod + mod ) % mod ) ;
    system ("pause") ; return 0 ;
}

ZROI#999

原文:https://www.cnblogs.com/Equinox-Flower/p/11486647.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!