NC16576 [NOIP2012]摆花
题目
题目描述
小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共m 盆。通过调查顾客的喜好,小明列出了顾客最喜欢的n 种花,从1 到n 标号。为了在门口展出更多种花,规定第i 种花不能超过ai 盆,摆花时同一种花放在一起,且不同种类的花需按标号的从小到大的顺序依次摆列。
试编程计算,一共有多少种不同的摆花方案。
输入描述
第一行包含两个正整数n和m,中间用一个空格隔开。
第二行有n个整数,每两个整数之间用一个空格隔开,依次表示a1、a2、……an。
输出描述
输出只有一行,一个整数,表示有多少种方案。注意:因为方案数可能很多,请输出方案数对1000007取模的结果。
示例1
输入
2 4 3 2
输出
2
说明
有2种摆花的方案,分别是(1,1,1,2),(1,1,2,2)。括号里的1和2表示两种花,比如第一个方案是前三个位置摆第一种花,第四个位置摆第二种花。
备注
对于20%数据,有0<n≤8,0<m≤8,0≤ai≤8;
对于50%数据,有0<n≤20,0<m≤20,0≤ai≤20;
对于100%数据,有0<n≤100,0<m≤100,0≤ ai≤100。
题解
知识点:背包dp,计数dp。
可以看作一个多重背包,每种花是看作物品,花的盆数是物品数量。于是有转移方程:
表示考虑到第 盆花已经摆了 盆时的方案数是考虑到 盆摆了 盆的方案数的总和,可以用前缀和优化,普通的多重背包就不一定可以这样优化qwq。
可以滚动数组优化空间。
题外话
一个经典模型 ,每个整数位置和值不同就是方案不同,问有多少种方案。
考虑把整数当成多个不加区分的 合在一起的结果,用不加区分的隔板分隔不同的整数。例如:111|11|1111|1|1,就分出了 。
于是对于这个模型,有 个隔板, 个 ,一共会有 个位置放 和隔板,先放隔板有 种方案,剩下的放 有 种方案,共计 种方案。
注意 是必须的,如果 则可以通过 的变形使得符合条件。
但本题是 ,就不能用这个经典模型了。
其实经典模型是个完全背包,而本题则是多重背包。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> using namespace std; const int mod = 1000007; int a[107], dp[107], sum[107];///第i种花,一共摆了j个 int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n, m; cin >> n >> m; dp[0] = 1; for (int i = 1;i <= n;i++) cin >> a[i]; for (int i = 1;i <= n;i++) { sum[0] = dp[0]; for (int j = 1;j <= m;j++) sum[j] = (sum[j - 1] + dp[j]) % mod; for (int j = 0;j <= m;j++) dp[j] = (sum[j] - (j - a[i] - 1 < 0 ? 0 : sum[j - a[i] - 1]) + mod) % mod; } cout << dp[m] << '\n'; return 0; }
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/16584051.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧