很快地想出了一个不是很快的方法,反正很想知道那些3ms的是怎么做出来的。。。只能膜拜了orz
看来一眼觉得是状压dp然后就算了一下复杂度,首先因为n最大是10所以没层需要有2的10次方种情况,然后100层,每层最多的情况应该是C10 5也就是250种左右,勉强可以。
然后详细说一下过程,因为n最大是10,而且每个格子最多只能放一只panda,所以每层的熊猫数量为a[i]的情况肯定是CNa[i]种,然后把每种和之前的一种情况亦或一下就是新情况了。所以存储每一层可能出现的01情况的数量即可。
顺便说一下那个带comb的复杂的位运算式子是求所有字典序k的排列的。
贴代码
# include <stdio.h>
# include <string.h>
const int Mod = 1e9 + 7;
const int MAX_N = 10;
const int MAX_M = 100;
int A[MAX_M], B[MAX_N];
int N, M;
int dp[MAX_M + 1][1 << MAX_N];
void solve()
{
memset(dp , 0 , sizeof(dp));
dp[0][0] = 1;
int i, j;
for(i = 1 ; i <= M ; i++)
{
for(j = 0 ; j < (1 << N) ; j++)
{
if(!dp[i - 1][j])
continue;
int comb = (1 << A[i - 1]) - 1;
while(comb < 1 << N)
{
dp[i][comb ^ j] += dp[i - 1][j];
if(dp[i][comb ^ j] >= Mod)
dp[i][comb ^ j] -= Mod;
int x = comb & -comb, y = comb + x;
comb = ((comb & ~y) / x >> 1) | y;
}
}
}
int s = 0;
for(i = 0 ; i < N ; i++)
{
s <<= 1;
s |= B[i];
}
printf("%d\n", dp[M][s]);
}
int main()
{
while(~scanf("%d %d", &N, &M))
{
int i;
for(i = 0 ; i < M ; i++)
scanf("%d", &A[i]);
for(i = 0 ; i < N ; i++)
scanf("%d", &B[i]);
solve();
}
return 0;
}