Vijos_1792_摆花_(动态规划,多重集组合数)

描述


https://vijos.org/p/1792

共n种花,第i种花有a[i]个,要摆m个,同一种花连续且花按照序号从小到大排,问共有多少种摆花方案.

 

描述

小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共m盆。通过调查顾 客的喜好,小明列出了顾客最喜欢的n种花,从1到n标号。为了在门口展出更多种花,规定第i种花不能超过ai盆,摆花时同一种花放在一起,且不同种类的花 需按标号的从小到大的顺序依次摆列。试编程计算,一共有多少种不同的摆花方案。

格式

输入格式

【输入】
输入文件共2行。第一行包含两个正整数n和m,中间用一个空格隔开。第二行有n个整数,每两个整数之间用一个空格隔开,依次表示a1、a2、……an。

输出格式

【输出】
输出只有一行,一个整数,表示有多少种方案。注意:因为方案数可能很多,请输出方案数对1000007取模的结果。

样例1

样例输入1[复制]

2 4
3 2

样例输出1[复制]

2

限制

1S

提示

【输入输出样例说明】
有2种摆花的方案,分别是(1,1,1,2),(1,1,2,2)。括号里的1和2表示两种花,比如第一个方案是前三个位置摆第一种花,第四个位置摆第二种花。

来源

NOIP2012普及组第三题

 

分析


由于花按照序号排放,所以对于任意一个选定的集合,集合中花的摆放顺序是唯一的,所以一个集合对应一种方案.问题就转化成了求多重集组合数.

POJ_3046_Ant_Counting

上面这道题里有详细的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 }
View Code

 

posted @ 2016-05-25 14:57  晴歌。  阅读(517)  评论(0编辑  收藏  举报