【HDU】5155 Harry And Magic Box 【容斥原理】

传送门:【HDU】5155 Harry And Magic Box


题目分析:很容易发现容斥的方法,首先我们不管是否每一列都有星星,但是一定保证每一行至少一个星星,因此我们得到了一个方法,这时有方案数(c[m][1]+c[m][2]+...+c[m][m])^n,但是这里包括了不合法的情况,于是我们用容斥减掉。最后的答案就是:

这个就是用了容斥的方法把恰好为1~m-1个列为空的情况全部去掉了,只留下了所有列都非空的情况(注意一开始我们保证至少一列非空了的,因为要保证每一行都有一个数)。

具体这个容斥的原理我只是会用,想知道为什么可以,可以自己搜索下。

本题时间复杂度为O(50^2)的预处理以及每次O(m)的询问。(当然也可以O(50^3)预处理O(1)作答)。

PS:注意n和m其中一个为0就输出0,因为此时宝石无法放,也就没有放法这一说。


代码如下:


#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;

typedef long long LL ;

#define rep( i , a , b ) for ( int i = ( a ) ; i <  ( b ) ; ++ i )
#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define clr( a , x ) memset ( a , x , sizeof a )
#define cpy( a , x ) memcpy ( a , x , sizeof a )
#define ls ( o << 1 )
#define rs ( o << 1 | 1 )
#define lson ls , l , m
#define rson rs , m + 1 , r
#define rt o , l , r
#define root 1 , 1 , n
#define mid ( ( l + r ) >> 1 )

const int MAXN = 55 ;
const int mod = 1000000007 ;

int c[MAXN][MAXN] ;
LL sum[MAXN][MAXN] ;
int n , m ;

void preprocess () {
	clr ( c , 0 ) ;
	clr ( sum , 0 ) ;
	c[0][0] = 1 ;
	For ( i , 1 , 50 ) {
		c[i][0] = 1 ;
		For ( j , 1 , i ) {
			c[i][j] = ( c[i - 1][j - 1] + c[i - 1][j] ) % mod ;
			sum[i][1] = ( sum[i][1] + c[i][j] ) % mod ;
		}
		For ( j , 2 , 50 ) sum[i][j] = sum[i][j - 1] * sum[i][1] % mod ;
	}
}

void solve () {
	int ans = 0 ;
	LL sign = 1 ;
	rep ( i , 0 , m ) {
		ans = ( ans + sign * c[m][i] * sum[m - i][n] ) % mod ;
		sign = -sign ;
	}
	printf ( "%d\n" , ( ans % mod + mod ) % mod ) ;
}

int main () {
	preprocess () ;
	while ( ~scanf ( "%d%d" , &n , &m ) ) solve () ;
	return 0 ;
}


你可能感兴趣的:(HDU)