您的位置:首页 > 其它

【HDU】4901 The Romantic Hero 01背包

2014-07-31 19:15 525 查看
传送门:【HDU】4901 The Romantic Hero

题目分析:这个01背包好做。。。。因为S集合一定在T集合的左边,那么可以枚举集合的分割线,并且枚举出的方案要保证没有重复。方案数可以通过01背包求出。如果要保证不重复,其实只要保证分割线上的点要强制被取到就行了。像我就是保证S集合的最右端一定要被取到,然后T集合是没有限制的。

代码如下:

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

#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 - 1 ; i >= b ; -- i )
#define FOV( i , a , b ) for ( int i = a ; i >= b ; -- i )
#define CLR( a , x ) memset ( a , x , sizeof a )

typedef long long LL ;

const int MAXN = 1200 ;
const int mod = 1e9 + 7 ;

int num[MAXN] ;

int f[MAXN][MAXN] , a[MAXN][MAXN] ;

void solve () {
	int n ;
	scanf ( "%d" , &n ) ;
	FOR ( i , 1 , n )
		scanf ( "%d" , &num[i] ) ;
	CLR ( f , 0 ) ;
	f[0][0] = 1 ;
	FOR ( i , 1 , n ) {
		FOR ( v , 0 , 1024 ) {
			f[i][v] = f[i - 1][v] + f[i - 1][v ^ num[i]] ;
			if ( f[i][v] >= mod )
				f[i][v] -= mod ;
		}
		FOR ( v , 0 , 1024 )
			a[i][v] = f[i - 1][v ^ num[i]] ;
	}
	CLR ( f , 0 ) ;
	FOV ( i , n , 1 ) {
		FOR ( v , 0 , 1024 ) {
			f[i][v] += f[i + 1][v] ;
			f[i][v & num[i]] += f[i + 1][v] ;
			if ( f[i][v] >= mod )
				f[i][v] -= mod ;
			if ( f[i][v & num[i]] >= mod )
				f[i][v & num[i]] -= mod ;
		}
		f[i][num[i]] ++ ;
	}
//	FOV ( i , n , 1 )
//		FOV ( j , 3 , 0 )
//			printf ( "f[%d][%d] = %d\n" , i , j , f[i][j] ) ;
	int ans = 0 ;
	FOR ( i , 1 , n - 1 )
		FOR ( j , 0 , 1024 )
			ans = ( ans + ( LL ) a[i][j] * f[i + 1][j] ) % mod ;
	printf ( "%d\n" , ans ) ;
}

int main () {
	int T ;
	scanf ( "%d" , &T ) ;
	while ( T -- )
		solve () ;
	return 0 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: