博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ZROI#999
阅读量:5289 次
发布时间:2019-06-14

本文共 6240 字,大约阅读时间需要 20 分钟。

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

#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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
#define int long long#define pb push_backusing 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 ;}

\(70pts\)并不难,

不过我们的容斥会有些许变化.
我们发现题目可以简化为:
给定\(n\)个二进制数,任选一些数字,求有多少种选择方案使得选出来的数字按位or起来是每一位都是\(1\).
于是我们就令\(g(S)\)表示状态为\(S\)的盒子的个数.
\(f(T)\)表示\(\sum_{S\subseteq T}g(S)\).
那么不难想到有这样一个容斥:
\[\sum_{S\subseteq T}{2^{f(S)}(-1)^{m-|S|}}\]
那么我们考虑,这样求的复杂度怎么样.
计算\(g(S)\)是和读入一起的,所以复杂度是\(O(n*m)\)的.
而计算\(f(T)\)呢?我们考虑这到底是个什么玩意儿.
这其实是状态为\(T\)以及\(T\)的子集的盒子总数.
所以我们要枚举子集的子集,这样的复杂度你可能会认为是\(O(4^m)\)
但其实不是,而是\(O(3^m)\)的,这样的复杂度足以通过\(70pts\).
满分思路见代码后.
\(Code:\)

#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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
#define int long long#define pb push_back#define lowbit(x) ( ( x ) & ( - x ) )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 = 1e7 + 100 ;const int mod = 1e9 + 7 ;int n , g[N] , m , ans , f[N] , siz[N] , p[N] ;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 () , res = 0 ; while ( k -- ) res |= ( 1 << ( rint () - 1 ) ) ; ++ g[res] ; } for (int i = 0 ; i < maxsize ; ++ i) { for (int j = i ; j ; j = ( j - 1 ) & i ) f[i] += g[j] ; f[i] += g[0] ; } p[0] = 1 ; rep ( i , 1 , n ) p[i] = ( p[i-1] << 1 ) % mod ; for (int i = 1 ; i < maxsize ; ++ i) siz[i] = siz[i^lowbit(i)] + 1 ; for (int i = 0 ; i < maxsize ; ++ i) { int d = ( ( ( m - siz[i] ) & 1 ) ? - 1 : 1 ) ; ans = ( ( ans + p[f[i]] * d ) % mod + mod ) % mod ; } printf ("%lld\n" , ( ans % mod + mod ) % mod ) ; system ("pause") ; return 0 ;}

我们发现上面的复杂度瓶颈其实是在求\(f(T)\)的时候我们需要枚举子集的子集.

那么我们就考虑能否优化掉这个复杂度.经过一番思考我们发现,这是个高维前缀和问题.
所以需要使用\(FMT\),但这个题的\(FMT\)没有你想象的那个长得像\(FFT\)的亚子.
这个题目用到的\(FMT\)是一种经典的形式:子集和形式.
这里用到的十分简单,不需要卷积形式..
然后你考虑,对于每一个集合,
我们如果都能算出来它在每一位上分别缺一个\(1\)(即构成一个\(size-1\)的子集)的方案数之和,
那么我们就能从\(size\)\(1\)的子集一直递推到\(size\)\(m\)的子集,于是我们就愉快的解决了这个问题.
\(Code:\)

#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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
#define int long long#define pb push_back#define lowbit(x) ( ( x ) & ( - x ) )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 = 1e7 + 100 ;const int mod = 1e9 + 7 ;int n , g[N] , m , cnt , num , ans , p[N] , siz[N] ;signed main (int argc , char * argv[]) { n = rint () ; m = rint () ; int maxsize = 1 << m ; rep ( i , 1 , n ) { int k = rint () , res = 0 ; while ( k -- ) res |= ( 1 << ( rint () - 1 ) ) ; ++ g[res] ; } for (int i = 0 ; i < m ; ++ i) for (int j = 0 ; j < maxsize ; ++ j) if ( j & ( 1 << i ) ) g[j] += g[j^(1<

转载于:https://www.cnblogs.com/Equinox-Flower/p/11486647.html

你可能感兴趣的文章
【转】详解硬盘MBR
查看>>
bashrc 文件命令
查看>>
hdu4271 Find Black Hand 2012长春网络赛E题 最短编辑距离
查看>>
V7000初始化
查看>>
animate.css的使用
查看>>
Struts2 注释类型
查看>>
JSP中EL表达式语言不能使用的解决方法
查看>>
做XH2.54杜邦线材料-导线
查看>>
如何刻录cd音乐
查看>>
Codeforces Round #318(Div 1) 573A, 573B,573C
查看>>
51Nod 1091 线段重叠 贪心 区间重叠
查看>>
[翻译] NimbusKit
查看>>
POJ 2196
查看>>
熟悉下 mysql 的数据库导入导出
查看>>
5个数组Array方法: indexOf、filter、forEach、map、reduce使用实例(转)
查看>>
Machine Learning for hackers读书笔记(七)优化:密码破译
查看>>
Python基础第24天
查看>>
使用NPOI 做Excel导出
查看>>
L0/L1/L2范数(转载)
查看>>
[deviceone开发]-数据绑定示例
查看>>