bzoj1037 [ZJOI2008]生日聚会Party 插数dp

来源:互联网 发布:java移动鼠标方法 编辑:程序博客网 时间:2024/06/08 12:06

这个题首先要认清楚任意一个区间差不超过k个怎么理解

看到k一般想的是装压,但如果是状压的思路的话,就需要前k个满足某种条件,于是有可能会猜到前k个满足非全0或1,但这是显然错误的

由于仅仅考虑前k个并不能概括全体,而加状态也肯定是错的,就可以考虑离散前几个

设插数的位置为末尾,则只会对后缀产生影响,由于不符合条件可能有多个,就只用取最长的作为代表,

这样就可以记录它对每个代表后缀的长度  来dp

能这样dp的主要原因是后缀满足连续性,即上一阶段的后缀全部参与下一阶段的后缀,即增量是等价的,所以只用考虑一个最可能不合法的

码:

#include<iostream>#include<cstdio>using namespace std;#define P 12345678int n,m,i,j,k,l,K,f[305][160][25][25],ans;int main(){scanf("%d%d%d",&n,&m,&K);f[0][0][0][0]=1;for(i=0;i<n+m;i++)//总人数 {for(j=0;j<=n;j++)//男 for(k=0;k<=K;k++)//后缀男-女maxfor(l=0;l<=K;l++)//后缀女-男max{//这一个加入的是男f[i+1][j+1][k+1][max(l-1,0)]+=f[i][j][k][l];f[i+1][j][max(k-1,0)][l+1]+=f[i][j][k][l];f[i+1][j+1][k+1][max(l-1,0)]%=P;f[i+1][j][max(k-1,0)][l+1]%=P;}}for(i=0;i<=K;i++)for(j=0;j<=K;j++)ans+=f[n+m][n][i][j],ans%=P;printf("%d",ans);}