标程里用了非常漂亮的位操作,特摘录如下。
used 代表当前使用过的数字情况。move代表每一次使用的数字,比如134就是1101。b[used]代表在used情况下能够组成的序列数量。b[i] = ∑(b[i|j]+1) ,j 从1到maxn且j不能和i重叠(i&j == 0)。加1是只取到新的j这种情况。
细节地方需要仔细考虑。
#include
<
cstdio
>
#include < string >
int T, maxMove;
double b[ 3000 ];
double calc ( int used )
... {
if ( b[used] > -1 )
return b[used];
int move;
double nMove = 0;
for ( move = 1; move < maxMove; move ++ )
...{
if ( move & used )
continue;
nMove += 1 + calc ( used | move );
}
return b[used] = nMove;
}
int main ()
... {
//freopen ( "in.txt", "r", stdin );
scanf ( "%d", &T );
int i, x;
for ( i = 1; i <= T; i ++ )
...{
scanf ( "%d", &x );
maxMove = 1 << x;
memset ( b, 0xff, sizeof ( b ) );
printf ( "%d %d %.0f ", i, x, calc ( 0 ) );
}
return 0;
}
#include < string >
int T, maxMove;
double b[ 3000 ];
double calc ( int used )
... {
if ( b[used] > -1 )
return b[used];
int move;
double nMove = 0;
for ( move = 1; move < maxMove; move ++ )
...{
if ( move & used )
continue;
nMove += 1 + calc ( used | move );
}
return b[used] = nMove;
}
int main ()
... {
//freopen ( "in.txt", "r", stdin );
scanf ( "%d", &T );
int i, x;
for ( i = 1; i <= T; i ++ )
...{
scanf ( "%d", &x );
maxMove = 1 << x;
memset ( b, 0xff, sizeof ( b ) );
printf ( "%d %d %.0f ", i, x, calc ( 0 ) );
}
return 0;
}