2 条题解
-
0
本题使用记忆化搜索,但是好像有优秀的 DP 更快,这里讲记搜做法。
首先暴力 dfs 就可以拿到 50 分。
电风扇:
#include<bits/stdc++.h> #define int long long #define mod 1000000007 using namespace std; int k,n,a[20],ans,mp[100]; void dfs(int u){ if(u==n+1){ ++ans; if(ans>=mod)ans-=mod; } for(int i=1;i<=k;++i){ if(mp[u-1]!=i&&a[i]){ mp[u]=i,--a[i]; dfs(u+1); ++a[i]; } } } signed main(){ cin>>k; for(int i=1;i<=k;++i){ cin>>a[i]; n+=a[i]; } dfs(1); cout<<ans<<"\n"; return 0; }然后我们优化,由于相邻的不能涂同种颜色,所以直接 DP 比较困难,我们考虑记忆化搜索。
然后你的参数必须能够准确概括状态,注意到 非常大,但是 就不那么大,所以我们可以设:
dp[a][b][c][d][e][lst] 表示还能涂1,2,3,4,5个的颜色分别还有 ,,,,种,并且上一次涂的是还能用 次的颜色(现在只能用 次了)。
所以如果你这一次用的是还能用一次的一个,有 种选择,但是如果你上一次用的还能用两次的,他这次就会加入到还能用一次的里面,所以如果 则这一次可用的颜色数会减一。
其他的同理。
#include<bits/stdc++.h> #define int long long #define mod 1000000007 using namespace std; int n,k,a[20]; int dp[16][16][16][16][16][6]; int t[6]; int dfs(int a,int b,int c,int d,int e,int lst){ if(dp[a][b][c][d][e][lst]!=-1)return dp[a][b][c][d][e][lst]; if(a+b+c+d+e==0)return 1; int ans=0; if(a)ans+=(a-(lst==2))*dfs(a-1,b,c,d,e,1); if(b)ans+=(b-(lst==3))*dfs(a+1,b-1,c,d,e,2); if(c)ans+=(c-(lst==4))*dfs(a,b+1,c-1,d,e,3); if(d)ans+=(d-(lst==5))*dfs(a,b,c+1,d-1,e,4); if(e)ans+=e*dfs(a,b,c,d+1,e-1,5); dp[a][b][c][d][e][lst]=ans%mod ; return ans%mod; } signed main() { cin>>k; for(int i=1;i<=k;++i){ cin>>a[i];++t[a[i]]; } memset(dp,-1,sizeof dp); cout<<dfs(t[1],t[2],t[3],t[4],t[5],0); return 0; }
- 1
信息
- ID
- 303
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 6
- 标签
- (无)
- 递交数
- 31
- 已通过
- 10
- 上传者