题意:
给出a,b,c三种物品,每种物品有A,B,C件,将所有的物品排成一列,每种物品不能连续出现aa,bb,cc次,问有多少种排列方式。
解题思路:
很明显的dp,但是转移不好想。
首先我们需要思维i,j,k,l分别表示当前用了i件a,j件b,k件c,序列末尾是第l种物品,dp[i][j][k][l]就表示这个状态有多少种排列方式。l是不可少的,只用三维的话怎么也做不对。
转移的话就是,以l=0为例 dp[i+s][j][k][0]=dp[i+s][j][k][0]+dp[i][j][k][1]+dp[i][j][k][2];s为1到aa之间的数。
然后对l=1,l=2的情况也做同意的操作,就可以了。
代码:
#include <bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int dp[55][55][55][5];
int main()
{
int n[4], d[4], t, s, i, j, k;
cin>>t;
while(t--)
{
cin>>n[0]>>n[1]>>n[2]>>d[0]>>d[1]>>d[2];
memset(dp, 0, sizeof(dp));
for(i=0; i<=n[0]; i++)
{
for(j=0; j<=n[1]; j++)
{
for(k=0; k<=n[2]; k++)
{
for(s=1; s<=min(n[0]-i, d[0]); s++)
{
if(i==0 && j==0 && k==0)
{
dp[i+s][j][k][0]=(dp[i+s][j][k][0]+1)%mod;
}
else
dp[i+s][j][k][0]=((dp[i][j][k][1]+dp[i][j][k][2])%mod+dp[i+s][j][k][0])%mod;
}
for(s=1; s<=min(n[1]-j, d[1]); s++)
{
if(i==0 && j==0 && k==0)
{
dp[i][j+s][k][1]=(dp[i][j+s][k][1]+1)%mod;
}
else
dp[i][j+s][k][1]=((dp[i][j][k][2]+dp[i][j][k][0])%mod+dp[i][j+s][k][1])%mod;
}
for(s=1; s<=min(n[2]-k, d[2]); s++)
{
if(i==0 && j==0 && k==0)
{
dp[i][j][k+s][2]=(dp[i][j][k+s][2]+1)%mod;
}
else
dp[i][j][k+s][2]=((dp[i][j][k][1]+dp[i][j][k][0])%mod+dp[i][j][k+s][2])%mod;
}
}
}
}
long long ans=0;
ans=((dp[n[0]][n[1]][n[2]][0]+dp[n[0]][n[1]][n[2]][1])%mod+dp[n[0]][n[1]][n[2]][2])%mod;
cout<<ans<<endl;
}
}