【bzoj 1037】生日聚会Party(DP)
2018-02-27 09:31
183 查看
传送门biu~
如果求一个01序列满足任意一段0和1的数量差不超过k,可以考虑在已满足条件的某序列后面填一位0或1,只考虑当前序列的所有后缀是否满足0和1数量差不超过k的条件。这样我们就判断了最终序列的所有前缀的后缀是否满足条件,即任意一段0和1的数量差是否超过k。
令f[i][j][x][y]表示有i个男孩j个女孩的序列的所有后缀中男孩数量比女孩最多多x,女孩数量比男孩数量最多多y的方案数。
那么序列后填一个男孩时f[i+1][j][x+1][max(y-1,0)]+=f[i][j][x][y];填一个女孩时f[i][j+1][max(x-1,0)][y+1]+=f[i][j][x][y]。
如果求一个01序列满足任意一段0和1的数量差不超过k,可以考虑在已满足条件的某序列后面填一位0或1,只考虑当前序列的所有后缀是否满足0和1数量差不超过k的条件。这样我们就判断了最终序列的所有前缀的后缀是否满足条件,即任意一段0和1的数量差是否超过k。
令f[i][j][x][y]表示有i个男孩j个女孩的序列的所有后缀中男孩数量比女孩最多多x,女孩数量比男孩数量最多多y的方案数。
那么序列后填一个男孩时f[i+1][j][x+1][max(y-1,0)]+=f[i][j][x][y];填一个女孩时f[i][j+1][max(x-1,0)][y+1]+=f[i][j][x][y]。
#include<bits/stdc++.h> using namespace std; const int mod=12345678; int n,m,k,ans,f[155][155][25][25]; int main(){ scanf("%d%d%d",&n,&m,&k); f[0][0][0][0]=1; for(int i=0;i<=n;++i){ for(int j=0;j<=m;++j){ for(int x=0;x<=k;++x){ for(int y=0;y<=k;++y){ if(x+1<=k) f[i+1][j][x+1][max(y-1,0)]=(f[i+1][j][x+1][max(y-1,0)]+f[i][j][x][y])%mod; if(y+1<=k) f[i][j+1][max(x-1,0)][y+1]=(f[i][j+1][max(x-1,0)][y+1]+f[i][j][x][y])%mod; } } } } for(int i=0;i<=k;++i) for(int j=0;j<=k;++j) ans=(ans+f [m][i][j])%mod; printf("%d\n",ans); return 0; }
相关文章推荐
- bzoj1037 [ZJOI2008]生日聚会Party(dp)
- BZOJ 1037: [ZJOI2008]生日聚会Party(区间dp)
- bzoj1037:[ZJOI2008]生日聚会Party[DP]
- [BZOJ1037][ZJOI2008][DP]生日聚会Party
- BZOJ.1037.[ZJOI2008]生日聚会Party(DP)
- BZOJ 1037: [ZJOI2008]生日聚会Party DP
- BZOJ 1037-生日聚会Party(DP)
- BZOJ 1037 [ZJOI2008]生日聚会Party(单调DP)
- HYSBZ/BZOJ 1037 [ZJOI2008] 生日聚会Party - dp
- [BZOJ1037][ZJOI2008]生日聚会Party dp
- 【BZOJ1037】[ZJOI2008]生日聚会Party【计数DP】【特殊的姿势】
- bzoj 1037 [ZJOI2008]生日聚会Party(DP)
- [bzoj1037][DP]生日聚会party
- BZOJ 1037: [ZJOI2008]生日聚会Party DP
- bzoj1037: [ZJOI2008]生日聚会Party(dp)
- [bzoj1037][ZJOI2008]生日聚会Party dp
- BZOJ 1037 生日聚会Party(DP)
- bzoj 1037: [ZJOI2008]生日聚会Party dp
- bzoj 1037: [ZJOI2008]生日聚会Party (dp)
- [BZOJ 1037][ZJOI2008]生日聚会Party(DP)