【TJU】4087 box DP

4087.   box
Time Limit: 1.0 Seconds   Memory Limit: 65536K
Total Runs: 100   Accepted Runs: 26



Tuhao and his two small partners participated in the tournament.But in the end, they lost the chance to finish a mathematical problem.After the competition,Tuhao recalled that year in high school math class on a variety of tragedy.
One day, the math teacher give Tuhao a question:if you have 5 boxes in a line(every boxes are different) and you have 4 kinds of balls.you must put an ball in every box, and all balls can take unlimited. How many kinds of way of placing? Tuhao solve this problem easily.But he has another question to you.if we have N boxes, and we have m kind of balls, and you can't use all kinds of balls because Tuhao must have one kind ball at least to play with his partners...

Input

There will be multiple cases to consider. The first input will be a number T(0 < T ≤ 50) indicating how many cases with which you will deal. Following this number will be pairs of integers giving values for N and M, in that order. You are guaranteed that 1 ≤ N < 500, 1 ≤ M < 10, Each N M pair will occur on a line of its own. N and M will be separated by a single space.

Output

For each case display a line containing the case number (starting with 1 and increasing sequentially), and the kinds of way of placing. The desired format is illustrated in the sample shown below.(p.s. the answer should be module 200000007)

Sample Input

2
1 1
8 3

Sample Output

Case 1: 0
Case 2: 765


传送门:【TJU】4087 box


题目大意:给你n个不同的盒子,m种个数不限球(n <= 500 , m <= 10),问有多少种方案使得每个盒子中只有一个球且所用的种类不超过m-1种。


题目分析:根据题目数据来看,我们可以直接用状态压缩来做。

用二进制表示选择了球的种类。

那么处理到第i个盒子时所用的种类为 j 的状态转移方程就是dp[ i ][ j | ( 1 << k ) ] += dp[ i - 1 ][ j ](k = 0 ~ m - 1)。

不管题目的使用种类限制,则答案就是最后所有种类数相加。

由于不能使用所有的球,所以答案最后还要减去dp[ n ][ ( 1 << m ) - 1 ]。


代码如下:


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

#define clear( A , X ) memset ( A , X , sizeof A )

const int maxN = 10 ;
const int mod = 200000007 ;

int dp[2][1 << maxN] ;

void work () {
	int n , m ;
	scanf ( "%d%d" , &n , &m ) ;
	int mm = 1 << m , cur = 0 ;
	clear ( dp , 0 ) ;
	dp[0][0] = 1 ;
	for ( int i = 1 ; i <= n ; ++ i ) {
		cur ^= 1 ;
		clear ( dp[cur] , 0 ) ;
		for ( int j = 0 ; j < mm ; ++ j ) {
			for ( int k = 0 ; k < m ; ++ k ) {
				dp[cur][j | ( 1 << k )] += dp[cur ^ 1][j] ;
				if ( dp[cur][j | ( 1 << k )] >= mod ) dp[cur][j | ( 1 << k )] -= mod ;
			}
		}
	}
	int ans = 0 ;
	for ( int i = 0 ; i < mm - 1 ; ++ i ) {
		ans += dp[cur][i] ;
		if ( ans >= mod ) ans -= mod ;
	}
	printf ( "%d\n" , ans ) ;
}

int main () {
	int T , cas ;
	for ( scanf ( "%d" , &T ) , cas = 1 ; cas <= T ; ++ cas ) {
		printf ( "Case %d: " , cas ) ;
		work () ;
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值