题意:
给你n种染料,每种染料可以使用Ci次,同一种染料不能连续使用,求用完所有染料的方案数为多少种?
思路:
纯动态规划,我们用dp[a][b][c][d][e][last]描述一个还可以使用一次的染料为a种,还可以使用两次的染料为b种,.....,可以使用五次的染料为f种时上一次染色为使用还可以使用last次的染料。
我们可以分析状态是怎么来的得出状态转化方程,例如,dp[a][b][c][d][e][1]时,如果上上次不为2,则上一次则使用的为a+1种染料的其中一种,如果上上次为2,则说明上一次(a+1)种有一种不能使用,所以为a种中的其中一种。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define inf 1000000007
#define eps 0.00000001
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn=100005;
inline int read()
{
char c=getchar();
int f=1, x=0;
while(c>'9'||c<'0')
{
if(c=='-')
{
f=-1;
}
c=getchar();
}
while(c<='9'&&c>='0')
{
x=(x<<3)+(x<<1)+(c^48);
c=getchar();
}
return f*x;
}
ll dp[20][20][20][20][20][10], a[10];
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
int c;
scanf("%d",&c);
a[c]++;
}
dp[a[1]][a[2]][a[3]][a[4]][a[5]][1]=1;
for(int r=n;r>=0;r--)
{
for(int l=n;l>=0;l--)
{
for(int k=n;k>=0;k--)
{
for(int j=n;j>=0;j--)
{
for(int i=n;i>=0;i--)
{
ll p=0;
for(int o=1;o<=5;o++)
{
if(o==2)
{
p=p+dp[i+1][j][k][l][r][o]*(i);
p=p%inf;
}
else
{
p=p+dp[i+1][j][k][l][r][o]*(i+1);
p=p%inf;
}
}
dp[i][j][k][l][r][1]=max(dp[i][j][k][l][r][1],p);
p=0;
for(int o=1;o<=5;o++)
{
if(i!=0)
{
if(o==3)
{
p=p+dp[i-1][j+1][k][l][r][o]*(j);
p=p%inf;
}
else
{
p=p+dp[i-1][j+1][k][l][r][o]*(j+1);
p=p%inf;
}
}
}
dp[i][j][k][l][r][2]=max(dp[i][j][k][l][r][2],p);
p=0;
for(int o=1;o<=5;o++)
{
if(j!=0)
{
if(o==4)
{
p=p+dp[i][j-1][k+1][l][r][o]*(k);
p=p%inf;
}
else
{
p=p+dp[i][j-1][k+1][l][r][o]*(k+1);
p=p%inf;
}
}
}
dp[i][j][k][l][r][3]=max(dp[i][j][k][l][r][3],p);
p=0;
for(int o=1;o<=5;o++)
{
if(k!=0)
{
if(o==5)
{
p=p+dp[i][j][k-1][l+1][r][o]*l;
p=p%inf;
}
else
{
p=p+dp[i][j][k-1][l+1][r][o]*(l+1);
p=p%inf;
}
}
}
dp[i][j][k][l][r][4]=max(dp[i][j][k][l][r][4],p);
p=0;
for(int o=1;o<=5;o++)
{
if(l!=0)
{
p=p+dp[i][j][k][l-1][r+1][o]*(r+1);
p=p%inf;
}
}
dp[i][j][k][l][r][5]=max(dp[i][j][k][l][r][5],p);
//printf("%d\n",dp[1][1][1][0][0][0]);
}
}
}
}
}
cout << dp[0][0][0][0][0][1] << endl;
return 0;
}

京公网安备 11010502036488号