[ZJOI2008]生日聚会

P2592 [ZJOI2008]生日聚会

\(n\)个男孩和\(m\)个女孩坐成一排,求任意一段区间内男孩和女孩的数量之差不超过\(K\)的方案数.

\(f[i][j][x][y]\)应该是前\(i\)个人中有\(j\)个是男生,以当前点为结尾的任意一段不超过\(k\)的区间男生比女生最多多\(x\)人,女生比男生最多多\(y\)人的方案数

设状态的时候注意,这一题中两维的状态根本无法描述全部情况,至少开第三维,然而还是不能解决问题,考虑到数据范围很小,就开到了第四维.

采用刷表法更方便.\(f[0][0][0][0]=1.\)

这样搞可以保证转移的合法性,最终统计答案的时候就直接把使用的\(f[n+m][m][i][j]\)加起来就可以了.

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int INF=1e9+7;
inline LL read(){
    register LL x=0,f=1;register char c=getchar();
    while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
    while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar();
    return f*x;
}

const int MAXN=155;
const int MAXK=21;
const int mod=12345678;

int f[MAXN<<1][MAXN][MAXK][MAXK];
int n,m,K,ans;

int main(){
    n=read(),m=read(),K=read();
    f[0][0][0][0]=1;
    for(int i=0;i<=n+m-1;i++)
    for(int j=0;j<=n;j++)
    for(int x=0;x<=K;x++)
    for(int y=0;y<=K;y++)
        if(f[i][j][x][y]){
            if(j+1<=n&&x+1<=K) (f[i+1][j+1][x+1][max(y-1,0)]+=f[i][j][x][y])%=mod;
            if(i-j+1<=m&&y+1<=K) (f[i+1][j][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+=f[n+m][n][i][j])%=mod;
    printf("%d\n",ans);
}

猜你喜欢

转载自www.cnblogs.com/lizehon/p/10630374.html