题目描述
小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共m盆。通过调查顾客的喜好,小明列出了顾客最喜欢的n种花,从1到n标号。为了在门口展出更多种花,规定第i种花不能超过ai盆,摆花时同一种花放在一起,且不同种类的花需按标号的从小到大的顺序依次摆列。
试编程计算,一共有多少种不同的摆花方案。
输入输出格式
输入格式:
第一行包含两个正整数n和m,中间用一个空格隔开。
第二行有n个整数,每两个整数之间用一个空格隔开,依次表示a1、a2、……an。
输出格式:
输出只有一行,一个整数,表示有多少种方案。注意:因为方案数可能很多,请输出方案数对1000007取模的结果。
输入输出样例
输入样例#1:
2 4 3 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。
NOIP 2012 普及组 第三题
———————————————————我是分割线——————————————————————————————
一道DP水题
可以这样想:当考虑(第x种花,共选完y朵)的状态时,结果可以从 【当前这种花选i朵(i<=ai)】+(考虑第x-1种花,共选完y-i朵)这样的方案数得出,而得出的方法就是简单地数值累加。
因此,我们就能类似想到 有限背包的dp算法——从后往前计算;
这种算法的最原始版就是直接三重循环实现
加上空间优化到一维后(优化方法同有限背包优化),解决这题的数据范围就绰绰有余了
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 class su 8 { 9 private: 10 int s[101],d[101][101]; 11 int n,m; 12 public: 13 su() 14 { 15 n=0;m=0; 16 memset(s,0,sizeof(s)); 17 memset(s,0,sizeof(d)); 18 } 19 void input() 20 { 21 int i; 22 cin>>n>>m; 23 for(i=1;i<=n;i++) 24 cin>>s[i]; 25 for(i=0;i<=n;i++) 26 d[i][0]=1; 27 put(); 28 } 29 void put() 30 { 31 int i,j,k,t; 32 for(i=1;i<=n;i++) 33 for(j=1;j<=m;j++) 34 { 35 t=j; 36 if(s[i]<j) 37 t=s[i]; 38 for(k=0;k<=t;k++) 39 d[i][j]=(d[i][j]+d[i-1][j-k])%1000007; 40 } 41 } 42 ~su() 43 { 44 cout<<d[n][m]<<endl; 45 } 46 }; 47 int main() 48 { 49 std::ios::sync_with_stdio(false); 50 su ss; 51 ss.input(); 52 return 0; 53 }