题目大意
给n个数,从中任意选出一些数,使这些数能分成和相等的两组。
求有多少种选数的方案。
Data Constraint
题解
这题用到了 meet in the middle 的思想,或者说是折半搜索。
先将n分为两半,每一半
SRC
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std ;
#define N 20 + 10
#define M 2000 + 10
#define K 60000 + 10
typedef long long ll ;
struct Stype {
ll x ;
ll s ;
} s1[K] , s2[K] ;
bool vis[M][M] ;
ll a[N] ;
ll c[K] , d[K] ;
int n , tot1 , tot2 , Sign = 0 ;
ll ans ;
bool cmp( Stype a , Stype b ) { return a.s < b.s ; }
void DFS( int k , int m , ll sum , ll sta ) {
if ( k > m ) {
if ( !Sign ) s1[++tot1].x = sta , s1[tot1].s = sum ;
else s2[++tot2].x = sta , s2[tot2].s = sum ;
return ;
}
for (int c = -1 ; c <= 1 ; c ++ )
DFS( k + 1 , m , sum + a[k] * c , sta | ((ll)(c != 0) << (k - Sign - 1)) ) ;
}
void Calc() {
for (int i = 1 ; i <= c[0] ; i ++ ) {
for (int j = 1 ; j <= d[0] ; j ++ ) {
if ( vis[c[i]][d[j]] ) continue ;
vis[c[i]][d[j]] = 1 ;
ans ++ ;
}
}
}
int main() {
scanf( "%d" , &n ) ;
for (int i = 1 ; i <= n ; i ++ ) scanf( "%lld" , &a[i] ) ;
DFS( 1 , n / 2 , 0 , 0 ) ;
Sign = n / 2 ;
DFS( n / 2 + 1 , n , 0 , 0 ) ;
sort( s1 + 1 , s1 + tot1 + 1 , cmp ) ;
sort( s2 + 1 , s2 + tot2 + 1 , cmp ) ;
if ( s1[1].s < s2[1].s ) swap( s1 , s2 ) , swap( tot1 , tot2 ) ;
int j = 1 ;
vis[0][0] = 1 ;
for (int i = 1 ; i <= tot1 && j <= tot2 ; ) {
while ( s1[i].s > s2[j].s && j <= tot2 ) j ++ ;
if ( j > tot2 ) break ;
if ( s1[i].s < s2[j].s ) { i ++ ; continue ; }
c[0] = d[0] = 1 ;
c[1] = s1[i].x ;
d[1] = s2[j].x ;
int k ;
for (k = i + 1 ; k <= tot1 ; k ++ ) {
if ( s1[k].s != s1[i].s ) { k -- ; break ; }
c[++c[0]] = s1[k].x ;
}
i = k + 1 ;
for (k = j + 1 ; k <= tot2 ; k ++ ) {
if ( s2[k].s != s2[j].s ) { k -- ; break ; }
d[++d[0]] = s2[k].x ;
}
j = k + 1 ;
Calc() ;
}
printf( "%lld\n" , ans ) ;
return 0 ;
}
以上.