传送门:【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 ;
}