以「前 i 种花摆 j 盆的方案数」为状态,转移是长度 a_i+1 的滑动窗口和:前缀和把单格压到 O(1),一维滚动 O(n·m) 完成计数。
OJ: roj
题目 ID: 3596
难度:普及-
标签:动态规划多重背包前缀和python
创建: 2026-10-02 09:40
更新: 2026-10-07 13:50
题目描述
有
输入格式:第一行
输出格式:一个整数,表示方案数对
样例输入:2 4 / 3 2 样例输出:2
数据范围:
思路
设
参考代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-10-02 09:40
# update_at: 2026-10-02 09:40
import sys
from itertools import accumulate
MOD = 1000007 # 题面指定的模数(不是常见的 10^9+7)
def solve() -> None:
data = iter(map(int, sys.stdin.buffer.read().split()))
n, m = next(data), next(data)
caps: list[int] = [min(next(data), m) for _ in range(n)] # 超过 m 的上限永远用不到
# dp[x] = 摆 x 盆花的方案数;逐种花做「长度 cap+1 的滑动窗口和」
dp = [0] * (m + 1)
dp[0] = 1 # 一种花都不摆
for cap in caps:
pre = list(accumulate(dp, initial=0)) # pre[x] = 摆前若干盆的方案数前缀和
# 新方案数 = 窗口 dp[x-cap..x] 的和 = pre[x+1] - pre[x-cap](下标截到 0)
dp = [(pre[x + 1] - pre[max(x - cap, 0)]) % MOD for x in range(m + 1)]
print(dp[m])
if __name__ == "__main__":
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-06 14:55
* update_at: 2026-10-06 14:55
*/
#include <cstdio>
using namespace std;
typedef long long ll;
const int MOD = 1000007; // 题面指定的模数
int n, m;
int a[105]; // 每种花最多摆的盆数
int dp[105]; // dp[j] = 当前阶段恰好摆 j 盆的方案数
int pre[105]; // pre[j] = dp[0..j] 的前缀和
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
if (a[i] > m) a[i] = m; // 超过 m 的上限永远用不到
}
dp[0] = 1; // 一种花都不摆,只有摆 0 盆一种方案
for (int i = 1; i <= n; i++) {
int cap = a[i];
// 先对旧 dp 做前缀和
pre[0] = dp[0];
for (int j = 1; j <= m; j++) {
pre[j] = pre[j - 1] + dp[j];
if (pre[j] >= MOD) pre[j] -= MOD;
}
// 用前缀和差分求滑动窗口和,得到新 dp
for (int j = 0; j <= m; j++) {
int left = j - cap - 1;
int val = pre[j];
if (left >= 0) {
val -= pre[left];
if (val < 0) val += MOD;
}
dp[j] = val;
}
}
printf("%d\n", dp[m]);
return 0;
}