题意:
给你3种水果的数量,和水果分别连续吃的最大天数。问你猴子吃水果有多少种方案。
POINT:
记忆化搜索,一开始(pre=-1)可以吃3种水果,然后换着吃搜就好了。
搜到0 0 0肯定是1。
搜到只剩下一种水果了,那就要看看能不能一次吃光了。因为可以剩下的水果会大于 最大连续天数。
dp初始化不能为0,可以-1,然后剪枝。因为答案为0的情况挺多的。所以-1比较好,不会超时。
我另开了vis数组。
#include<iostream>
#include<stdio.h>
#include<queue>
#include<vector>
#include<string.h>
#include<algorithm>
using namespace std;
#define LL long long
const LL mod=1000000007;
LL dp[55][55][55][4];
LL d1,d2,d3;
int vis[55][55][55][4];
LL dfs(LL x,LL y,LL z,LL pre)
{
LL num=0;
LL k=0;
if(x!=0) k=1,num++;
if(y!=0) k=2,num++;
if(z!=0) k=3,num++;
if(num==0) return 1;
if(num==1){
if(k==1&&x<=d1) return 1;
if(k==2&&y<=d2) return 1;
if(k==3&&z<=d3) return 1;
return 0;
}
if(pre!=-1&&vis[x][y][z][pre]) return dp[x][y][z][pre];
LL xx=min(x,d1);
LL yy=min(y,d2);
LL zz=min(z,d3);
LL ans=0;
if(pre==-1){
for(LL i=1;i<=xx;i++){
(ans+=dfs(x-i,y,z,1))%=mod;
}
for(LL i=1;i<=yy;i++){
(ans+=dfs(x,y-i,z,2))%=mod;
}
for(LL i=1;i<=zz;i++){
(ans+=dfs(x,y,z-i,3))%=mod;
}
}
if(pre==1){
for(LL i=1;i<=yy;i++){
(ans+=dfs(x,y-i,z,2))%=mod;
}
for(LL i=1;i<=zz;i++){
(ans+=dfs(x,y,z-i,3))%=mod;
}
}
if(pre==2){
for(LL i=1;i<=xx;i++){
(ans+=dfs(x-i,y,z,1))%=mod;
}
for(LL i=1;i<=zz;i++){
(ans+=dfs(x,y,z-i,3))%=mod;
}
}
if(pre==3){
for(LL i=1;i<=xx;i++){
(ans+=dfs(x-i,y,z,1))%=mod;
}
for(LL i=1;i<=yy;i++){
(ans+=dfs(x,y-i,z,2))%=mod;
}
}
if(pre!=-1) dp[x][y][z][pre]=ans,vis[x][y][z][pre]=1;
return ans;
}
int main()
{
LL T;
scanf("%lld",&T);
while(T--){
LL n1,n2,n3;
scanf("%lld%lld%lld%lld%lld%lld",&n1,&n2,&n3,&d1,&d2,&d3);
for(int i=0;i<=n1;i++)
for(int j=0;j<=n2;j++)
for(int k=0;k<=n3;k++)
for(int t=0;t<=3;t++)
vis[i][j][k][t]=0;
cout<<dfs(n1,n2,n3,-1)<<endl;
}
return 0;
}