https://ac.nowcoder.com/acm/problem/20265
dp[a][b][c][d][e][llast]可以涂满1个块的颜色有a个,2个块的有b个。。。。。当前末尾是可以涂last个颜色的块涂的。 可以发现,如果用了一次b,b就会少一个颜色,a会增加一个颜色。原理就是这样
#include<iostream> #include<cstring> #include<algorithm> using namespace std; const int maxn = 18; typedef long long ll; const ll mod = 1e9+7; ll dp[maxn][maxn][maxn][maxn][maxn][7];//a,b,c,d,e颜色last结尾 int list[200]; ll dfs(int a,int b,int c,int d,int e,int last){ if(dp[a][b][c][d][e][last] != -1) return dp[a][b][c][d][e][last]; if(a + b + c + d + e == 0) return 1; ll ans = 0; if(a) ans = (ans + 1LL*(a - (last == 2))*dfs(a-1,b,c,d,e,1))%mod; if(b) ans = (ans + 1LL*(b - (last == 3))*dfs(a+1,b-1,c,d,e,2))%mod; if(c) ans = (ans + 1LL*(c - (last == 4))*dfs(a,b+1,c-1,d,e,3))%mod; if(d) ans = (ans + 1LL*(d - (last == 5))*dfs(a,b,c+1,d-1,e,4))%mod; if(e) ans = (ans + 1LL*e*dfs(a,b,c,d+1,e-1,5))%mod;//没人可以转移到他 dp[a][b][c][d][e][last] = ans%mod; return dp[a][b][c][d][e][last]; } int cns[20]; int main(){ int n; memset(dp,-1,sizeof(dp)); scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&list[i]); cns[list[i]] ++;//长度是listi的颜色 } ll ans = dfs(cns[1],cns[2],cns[3],cns[4],cns[5],0); printf("%lld ",ans); return 0; }