JZOJ 5723. 贪婪人

题目

假设有一个 n m 的棋盘,除左上角的格子的数字为 0 外,每一个格子的数字为 [ 0 , S ] 中的任意一个整数。
每次走右边或者下面数字较大的那个格,如果数字一样大,则走右边。
问走过的格子上的数字之和为 S 的棋盘有多少种。

题解

对于 n , m , S 100 的,直接DP,设 f [ i ] [ j ] [ k ] 表示走到 ( i , j ) ,和为 k 的棋盘有多少个?这样子不好转移,因为考虑到有些格子对你走的路径没有影响。
那么 f [ i ] [ j ] [ k ] 只用记录那些确定了的方案数。

f [ i + 1 ] [ j ] [ k + l ] + = f [ i ] [ j ] [ k ] l

f [ i ] [ j + 1 ] [ k + l ] + = f [ i ] [ j ] [ k ] ( l + 1 )

l 是接下来和增加的量。
最下或最右的每个格子对答案的总贡献为 Σ G e b a n ( S k , m i ) f [ n ] [ i ] [ k ] ( S + 1 ) n m 1 2 ( n 1 + i 1 ) ( m i ) + Σ G e b a n ( S k , n i ) f [ i ] [ m ] [ k ] ( S + 1 ) n m 1 2 ( m 1 + i 1 ) ( n i )
n , m 2500 怎么做?
由于向右走和向下走是互不干扰的,所以可以分开搞。
f [ i ] [ j ] 表示向下走 i 步,和为 j 的方案数。
g [ i ] [ j ] 表示向右走 i 步,和为 j 的方案数。
然后卷一下就能够得到走到每个 ( i , m ) ( n , i ) 的方案数。
枚举总和,还有向右移的和。
时间复杂度 O ( n S 2 )

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 3005
#define M 105
#define mo 10007
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
int i,j,k,l,n,m,S,ans,temp,t,t1;
int f[N][M],g[N][M];
int x,y,z;
int jc[N+M],ny[N+M];
void add(int &x,int y){x=x+y>=mo?x+y-mo:x+y;}
int ksm(int x,int y){
    int rs=1;
    for(;y;y>>=1,x=(x*x)%mo)if(y&1)rs=(rs*x)%mo;
    return rs;
}
void pre(){
    int i,j;
    jc[0]=jc[1]=ny[0]=ny[1]=1;
    fo(i,2,N+M-10)jc[i]=(jc[i-1]*i)%mo;
    ny[N+M-10]=ksm(jc[N+M-10],mo-2);
    fd(i,N+M-11,2)ny[i]=(ny[i+1]*(i+1))%mo;
}
int C(int n,int m){
    return ((jc[n]*ny[m])%mo*ny[n-m])%mo;
}
int gb(int n,int m){
    return C(n+m-1,m-1);
}
int main(){
    pre();
    scanf("%d%d%d",&n,&m,&S);
    ans=0;
    f[0][0]=1;
    fo(i,0,n-1)
        fo(j,0,S)
            fo(k,0,S-j)
                add(f[i+1][j+k],f[i][j]*k%mo);
    g[0][0]=1;
    fo(i,0,m-1)
        fo(j,0,S)
            fo(k,0,S-j)
                add(g[i+1][j+k],g[i][j]*(k+1)%mo);
    fo(x,1,n-1){
        t=ksm(S+1,n*m-1-2*(m-1+x-1)-(n-x));
        t1=0;
        fo(y,0,S){
            fo(z,0,y){
                temp=gb(x-1,m-1)*f[x-1][z]%mo;
                temp=(temp*g[m-1][y-z])%mo;
                t1=(t1+temp*gb(S-y,n-x)%mo)%mo;
            }
        }
        add(ans,(t1*t)%mo);
    }
    fo(x,1,m-1){
        t=ksm(S+1,n*m-1-2*(n-1+x-1)-(m-x));
        t1=0;
        fo(y,0,S){
            fo(z,0,y){
                temp=gb(x-1,n-1)*g[x-1][z]%mo;
                temp=(temp*f[n-1][y-z])%mo;
                t1=(t1+temp*gb(S-y,m-x)%mo)%mo;
            }
        }
        add(ans,(t1*t)%mo);
    }
    printf("%d",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/huangjingyuan107/article/details/80427049
今日推荐