第七届山东省赛 Feed the monkey(dp)

96 篇文章 0 订阅
64 篇文章 0 订阅

题意:

给出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;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值