题面
题意
有n个木块,用k种颜色染色,每种油漆够染a[i]个,且a[i]之和为n,那么相邻两木块互不相同的染色方法有几种.
方法
此题难于记录状态,若用状态压缩则空间明显不够.
抓住每种颜色最多够刷5个木块且不一定要知道每一种颜色还剩下几个,可以开六位数组记录,前五个中,第i个记录剩余够刷i个木块的数量,最后一位记录上次用的颜色现在还够刷几个.
注意状态转移时,够刷i个的 -1 会使够刷i-1个的 +1.
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#define D dp[a1][a2][a3][a4][a5][last]
#define M 1000000007
#define ll long long
using namespace std;
ll dp[20][20][20][20][20][5],ans;
int n,m,have[6];
ll dfs(int a1,int a2,int a3,int a4,int a5,int last)
{
if(D!=-1) return D;
if(!a1&&!a2&&!a3&&!a4&&!a5) return 1;
ll res=0;
if(a1) res+=(a1-(last==1))*dfs(a1-1,a2,a3,a4,a5,0),res%=M;
if(a2) res+=(a2-(last==2))*dfs(a1+1,a2-1,a3,a4,a5,1),res%=M;
if(a3) res+=(a3-(last==3))*dfs(a1,a2+1,a3-1,a4,a5,2),res%=M;
if(a4) res+=(a4-(last==4))*dfs(a1,a2,a3+1,a4-1,a5,3),res%=M;
if(a5) res+=(a5-(last==5))*dfs(a1,a2,a3,a4+1,a5-1,4),res%=M;
D=res;
return res;
}
int main()
{
memset(dp,-1,sizeof(dp));
register int i,j,p;
cin>>m;
for(i=1;i<=m;i++)
{
scanf("%d",&p);
have[p]++;
}
cout<<dfs(have[1],have[2],have[3],have[4],have[5],0);
}