Vijos_1792_摆花_(动态规划,多重集组合数)
描述
共n种花,第i种花有a[i]个,要摆m个,同一种花连续且花按照序号从小到大排,问共有多少种摆花方案.
描述
小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共m盆。通过调查顾 客的喜好,小明列出了顾客最喜欢的n种花,从1到n标号。为了在门口展出更多种花,规定第i种花不能超过ai盆,摆花时同一种花放在一起,且不同种类的花 需按标号的从小到大的顺序依次摆列。试编程计算,一共有多少种不同的摆花方案。
格式
输入格式
【输入】
输入文件共2行。第一行包含两个正整数n和m,中间用一个空格隔开。第二行有n个整数,每两个整数之间用一个空格隔开,依次表示a1、a2、……an。
输出格式
【输出】
输出只有一行,一个整数,表示有多少种方案。注意:因为方案数可能很多,请输出方案数对1000007取模的结果。
限制
1S
提示
【输入输出样例说明】
有2种摆花的方案,分别是(1,1,1,2),(1,1,2,2)。括号里的1和2表示两种花,比如第一个方案是前三个位置摆第一种花,第四个位置摆第二种花。
来源
NOIP2012普及组第三题
分析
由于花按照序号排放,所以对于任意一个选定的集合,集合中花的摆放顺序是唯一的,所以一个集合对应一种方案.问题就转化成了求多重集组合数.
上面这道题里有详细的O(n*m)的算法介绍.这题数据水,O(n*m*m)的朴素算法也能过.
注意:
1.第二层循环里是 j<=m ,因为dp[i][j]表示的是前i种中拿j个(如果拿得过多方案数是0,不必考虑).
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn=100+5,mod=1e6+7; 5 int n,m; 6 int a[maxn]; 7 int dp[2][maxn]; 8 9 void solve(){ 10 dp[0][0]=dp[1][0]=1; 11 for(int i=1;i<=n;i++) 12 for(int j=1;j<=m;j++){ 13 if(j-1-a[i]>=0) dp[i&1][j]=(dp[(i-1)&1][j]+dp[i&1][j-1]-dp[(i-1)&1][j-a[i]-1]+mod)%mod; 14 else dp[i&1][j]=(dp[(i-1)&1][j]+dp[i&1][j-1])%mod; 15 } 16 printf("%d\n",dp[n&1][m]); 17 } 18 int main(){ 19 scanf("%d%d",&n,&m); 20 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 21 solve(); 22 return 0; 23 }