P4977 毒瘤之神异之旅 [动态规划]

毒 瘤 之 神 异 之 旅 毒瘤之神异之旅

题目描述见链接 .


最 初 想 法 \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.


正 解 部 分 \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) .


实 现 部 分 \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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值