毒瘤之神异之旅

题目描述见链接 .


<mstyle mathcolor="blue"> </mstyle> \color{blue}{最初想法}

F [ i , j ] F[i, j] F[i,j] 表示将 j j j 划分为 i i i 份的方案数, F [ i , j ] = F [ i 1 , j k ] F[i, j] = \sum F[i-1, j-k] F[i,j]=F[i1,jk] .
发现这样会使得形如 1 1 3. 的方案算多次: 1 1 3, 1 3 1, 3 1 1.


<mstyle mathcolor="red"> </mstyle> \color{red}{正解部分}

F [ i , j ] F[i, j] F[i,j] 表示将 i i i 划分成 j j j 份的方案数, 转移时不再一个一个数字添加, 而是整体往上叠,
可得 F [ i , j ] = F [ i 1 , j 1 ] + F [ i j , j ] F[i, j] = F[i-1, j-1] + F[i-j, j] F[i,j]=F[i1,j1]+F[ij,j], 分别表示包含 1 1 1 和 不包含 1 1 1 的情况 .
初值: F [ 0 , 0 ] = 1 F[0, 0] = 1 F[0,0]=1, 时间复杂度 O ( N 2 ) O(N^2) O(N2) .

鉴于上方的 d p dp dp 方式, 统计答案不能按传统顺序统计, 那么怎么统计呢 ? ? ?

我们可以对数字 x x x 单独考虑, 设 x x x 出现 y y y次 的方案为 n u m [ x , y ] num[x, y] num[x,y],
n u m [ x , y ] = x y x y + 1 num[x, y] = x至少出现y次的方案数 - x至少出现y+1的方案数 num[x,y]=xyxy+1 .
x y = F [ N x y , K y ] x至少出现y次的方案数 = F[N-xy, K-y] xy=F[Nxy,Ky] .

到这一步, 发现求出 n u m [ x , y ] num[x, y] num[x,y] 对统计答案好像并没有作用,
只需计算出 x y = F [ N x y , K y ] x至少出现y次的方案数 = F[N-xy, K-y] xy=F[Nxy,Ky] 即可.

于是答案等于 F [ N x y , K y ] x M \sum F[N-xy, K-y]*x^M F[Nxy,Ky]xM, 统计答案时间复杂度同样是 O ( N 2 ) O(N^2) O(N2) .


<mstyle mathcolor="red"> </mstyle> \color{red}{实现部分}

#include<bits/stdc++.h>
#define reg register

const int maxn = 5005;
const int mod = 1e9 + 7;

int N;
int K;
int M;
int Ans;
int F[maxn][maxn];

int Ksm(int a, int b){ int s = 1; while(b){ if(b&1)s=1ll*s*a%mod; a=1ll*a*a%mod; b>>=1;} return s; }

int main(){
        scanf("%d%d%d", &N, &K, &M);
        F[0][0] = 1;
        for(reg int i = 0; i <= N; i ++) F[i][i] = 1;
        for(reg int j = 1; j <= K; j ++)
                for(reg int i = j; i <= N; i ++)
                        F[i][j] = (F[i-1][j-1] + F[i-j][j]) % mod;
        for(reg int i = 1; i <= N; i ++)
                for(reg int j = 1; j <= K; j ++){
                        int num = 0;
                        if(i*j <= N) num += F[N-i*j][K-j];
                        int Amp = 1ll*num*Ksm(i, M) % mod;
                        Ans = (Ans + Amp) % mod;
                }
        printf("%d\n", Ans);
        return 0;
}