- http://ac.nbutoj.com/Problem/view.xhtml?id=1413
-
[1413] Weight
- 时间限制: 1000 ms 内存限制: 65535 K
- 问题描述
-
有n个砝码,每个砝码都有各自的重量。
那么这些砝码一共能称出哪些重量。 - 输入
-
输入一个正整数 n (1 <= n <= 100)表示一共有 n 个砝码。
接下来一行有n个正整数,每个正整数表示该砝码的重量,其重量不会超过100。 - 输出
-
从小到大输出所有可能的情况。
对于每行,包含两个数,前面一个数是能称出的重量,后面一个数是能称出该重量的不同情况的数量(就算重量相等的砝码也被视为不同的砝码)。
其数量要对100000007求余。 - 样例输入
-
4 1 2 3 4
- 样例输出
-
1 1 2 1 3 2 4 2 5 2 6 2 7 2 8 1 9 1 10 1
- 题解:
对于样例输入:
1 --> 1
2 --> 2 3
3 --> 3 4 5 6
4 --> 4 5 6 7 7 8 9 10
对于第N次遍历,就是第N个数与前N-1行分别相加的结果,还有不要忘了N本身也得算一次
不难得到dp方程: dp[a[i]+j]+=dp[j],当dp[j]!=0时;
代码:C++
1 #include<iostream> 2 #include<stdio.h> 3 #include<math.h> 4 #include<algorithm> 5 #include<string.h> 6 #include<string> 7 #include<ctime> 8 #include<queue> 9 #include<list> 10 #include<map> 11 #include<set> 12 #include<vector> 13 #include<stack> 14 #define INF 999999999 15 #define MAXN 10000000 16 using namespace std; 17 int dp[10010]; 18 int main() 19 { 20 int n; 21 while(~scanf("%d",&n)) 22 { 23 int i,j,a[110]; 24 memset(dp,0,sizeof(dp)); 25 for(i=1;i<=n;i++) 26 scanf("%d",&a[i]); 27 int s=0; 28 for(i=1;i<=n;i++) 29 { 30 s+=a[i]; //前i个值之和,也就是j遍历开始的最大值 31 for(j=s-a[i];j>0;j--) //这里必须是反过来的遍历,因为后面的遍历可能改变前面已经遍历过的值,不信可以debug试试 32 { 33 if(dp[j]) 34 { 35 dp[j+a[i]]+=dp[j]; 36 dp[j+a[i]]%=100000007; 37 } 38 } 39 dp[a[i]]++; //将本身的情况加进去 40 dp[a[i]]%=100000007; 41 } 42 for(i=1;i<=s;i++) 43 if(dp[i]) 44 { 45 printf("%d %d\n",i,dp[i]); 46 } 47 } 48 return 0; 49 }