这个题数据特别小,于是想到状压多维之流。
状压是比较麻烦的,虽然也能写,但多维dp明显要好写一些
根据15去设计状态是没有前途的,因为按颜色分一定会MLE
这时就考虑根据5分,这样不同颜色就离散了,就可以用离散数学的统计技巧来计算方案
f【已经涂了几个】【剩1次的颜色个数】【剩2次的颜色个数】【剩3次的颜色个数】【剩4次的颜色个数】【剩五次的颜色个数】【最后一次涂的是 剩几次的颜色】
第一维可以滚动数组,第二维可以计算,
然后枚举转移即可,这里加了一批可行性剪枝,能跑70ms
注:静态差错效果极好
码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define P 1000000007
long long f[2][16][16][16][16][6],K,a[6],sum,x,i,j,k,l,yi,er,san,si,wu,ci,o,last;
int main()
{
scanf("%lld",&K);
for(i=1;i<=K;i++)
scanf("%lld",&x),sum+=x,a[x]++;
f[1][a[2]][a[3]][a[4]][a[5]][0]=1;
for(ci=1;ci<=sum;ci++,o^=1)//进行第几次安放
{
memset(f[o],0,sizeof(f[o]));
for(er=0;er<=15;er++)//第二个余剩
{
if(er*2>sum-ci+1)continue;
for(san=0;san<=15;san++)//第三个余剩
{
if(er*2+san*3>sum-ci+1)continue;
for(si=0;si<=15;si++)//第四个余剩
{
if(er*2+san*3+si*4>sum-ci+1)continue;
for(wu=0;wu<=15;wu++)//第五个余剩
{
if(er*2+san*3+si*4+wu*5>sum-ci+1)continue;
yi=sum-ci+1-er*2-san*3-si*4-wu*5;
for(last=0;last<=5;last++)//上一个安放的
{
if(f[o^1][er][san][si][wu][last]==0)continue;
if(wu)f[o][er][san][si+1][wu-1][5]+= f[o^1][er][san][si][wu][last]*wu;//5->4
if(wu)f[o][er][san][si+1][wu-1][5]%=P;
if(si)f[o][er][san+1][si-1][wu][4]+= f[o^1][er][san][si][wu][last]*1ll*(last==5?si-1:si);//4->3
if(si)f[o][er][san+1][si-1][wu][4]%=P;
if(san)f[o][er+1][san-1][si][wu][3]+= f[o^1][er][san][si][wu][last]*1ll*(last==4?san-1:san);//3->2
if(san)f[o][er+1][san-1][si][wu][3]%=P;
if(er)f[o][er-1][san][si][wu][2]+= f[o^1][er][san][si][wu][last]*1ll*(last==3?er-1:er);//2->1
if(er)f[o][er-1][san][si][wu][2]%=P;
f[o][er][san][si][wu][1]+= f[o^1][er][san][si][wu][last]*1ll*(last==2?yi-1:yi);//1->0
f[o][er][san][si][wu][1]%=P;
}
}
}
}
}
}
printf("%lld",f[o^1][0][0][0][0][1]);
}