poj 3046 Ant Counting(多重集组合数) Ant Counting        

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 131072/65536K (Java/Other)
Total Submission(s) : 3   Accepted Submission(s) : 2
Problem Description
Bessie was poking around the ant hill one day watching the ants march to and fro while gathering food. She realized that many of the ants were siblings, indistinguishable from one another. She also realized the sometimes only one ant would go for food, sometimes a few, and sometimes all of them. This made for a large number of different sets of ants!

Being a bit mathematical, Bessie started wondering. Bessie noted that the hive has T (1 <= T <= 1,000) families of ants which she labeled 1..T (A ants altogether). Each family had some number Ni (1 <= Ni <= 100) of ants.

How many groups of sizes S, S+1, ..., B (1 <= S <= B <= A) can be formed?

While observing one group, the set of three ant families was seen as {1, 1, 2, 2, 3}, though rarely in that order. The possible sets of marching ants were:

3 sets with 1 ant: {1} {2} {3}
5 sets with 2 ants: {1,1} {1,2} {1,3} {2,2} {2,3}
5 sets with 3 ants: {1,1,2} {1,1,3} {1,2,2} {1,2,3} {2,2,3}
3 sets with 4 ants: {1,2,2,3} {1,1,2,2} {1,1,2,3}
1 set with 5 ants: {1,1,2,2,3}

Your job is to count the number of possible sets of ants given the data above.
 

 

Input
* Line 1: 4 space-separated integers: T, A, S, and B <br> <br>* Lines 2..A+1: Each line contains a single integer that is an ant type present in the hive
 

 

Output
* Line 1: The number of sets of size S..B (inclusive) that can be created. A set like {1,2} is the same as the set {2,1} and should not be double-counted. Print only the LAST SIX DIGITS of this number, with no leading zeroes or spaces.
 

 

Sample Input
3 5 2 3 1 2 2 1 3
 

 

Sample Output
10
 

分析:

多重集组合数也是由多重背包问题拓展出来的一类经典问题。这里仍然给大家讲2种方法:

①朴素方法:

状态:dp[i][j]:前i种中选j个可以组成的种数

决策:第i种选k个,k<=ant[i] && j-k>=0

转移:dp[i][j]=Σdp[i-1][j-k]

复杂度为O(B*Σant[i])即O(B*A)也即O(A^2),虽说这题A最大可到1e5,但是实际数据水,能过

 

②优化递推式

状态:dp[i][j]:前i种中选j个可以组成的种数

决策:第i种不选或者至少选一个

转移:

1.若不选,显然为dp[i-1][j]

2.若至少选一种,那么为dp[i][j-1]-dp[i-1][j-ant[i]-1]

我们这样来理解,dp[i][j-1] 理解为已经选了第i种一个,至于还选不选这里我们不管它,所以它可以用来代表至少选一个

但是dp[i][j-1]还有一层含义便是前i种中选j-1个可以组成的种数,所以它包含了选ant[i]个第i种,即dp[i-1][j-ant[i]-1],但

dp[i][j] 最多选ant[i]个第i种,所以最后要减去这一种。

所以 dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-ant[i]-1]

复杂度为O(T*B)

 1 #include <iostream>
 2 #include <cstring>
 3 #include <string>
 4 #include <algorithm>
 5 using namespace std;
 6 const int mod = 1000000;
 7 int dp[1005][100005];
 8 int main()
 9 {
10     int ant[1005];
11     int t, a, s, b;
12     cin >> t >> a >> s >> b;
13     memset(ant, 0, sizeof(ant));
14     int i;
15     int j;
16     for (i = 1; i <= a; i++)
17     {
18         cin >> j;
19         ant[j]++;
20     }
21     for (i = 0; i <= t; i++) dp[i][0] = 1;
22     dp[0][0] = dp[1][0] = 1;
23     for (i = 1; i <= t; i++)
24     {
25         for (j = 1; j <= b; j++)
26         {
27             if (j - ant[i] - 1 >= 0)
28             {//在取模时若出现了减法运算则需要先+Mod再对Mod取模,防止出现负数(如5%4-3%4为负数)  
29                 dp[i][j] = (dp[i - 1][j] + dp[i ][j - 1] - dp[i - 1][j - ant[i] - 1] + mod) % mod;
30             }
31             else
32             {
33                 dp[i][j] = (dp[i - 1][j] + dp[i][j - 1])%mod;
34             }     
35         }
36     }
37     int sum = 0;
38     for (i = s; i <= b; i++)
39         sum = (sum + dp[t][i]) % mod;
40     cout << sum << endl;
41     return 0;
42 }
View Code

为了节约空间%2;

#include<iostream>  
using namespace std;  
#define MOD 1000000  
int T, A, S, B;  
int ant[1005];  
int dp[2][100000];  
int ans;  
int main()  
{  
    scanf("%d%d%d%d", &T, &A, &S, &B);  
    for (int i = 1; i <= A; i++)  
    {  
        int aa;  
        scanf("%d", &aa);  
        ant[aa]++;  
    }  
    dp[0][0] = dp[1][0] = 1;  
    for (int i = 1; i <= T; i++)  
        for (int j = 1; j <= B; j++)  
            if (j - ant[i] - 1 >= 0) dp[i % 2][j] = (dp[(i - 1) % 2][j] + dp[i % 2][j - 1] - dp[(i - 1) % 2][j - ant[i] - 1] + MOD) % MOD;      //在取模时若出现了减法运算则需要先+Mod再对Mod取模,防止出现负数(如5%4-3%4为负数)  
            else dp[i % 2][j] = (dp[(i - 1) % 2][j] + dp[i % 2][j - 1]) % MOD;  
    for (int i = S; i <= B; i++)  
        ans = (ans + dp[T % 2][i]) % MOD;  
    printf("%d
", ans);  
    return 0;  
}  
View Code
 
Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 131072/65536K (Java/Other)
Total Submission(s) : 3   Accepted Submission(s) : 2
Problem Description
Bessie was poking around the ant hill one day watching the ants march to and fro while gathering food. She realized that many of the ants were siblings, indistinguishable from one another. She also realized the sometimes only one ant would go for food, sometimes a few, and sometimes all of them. This made for a large number of different sets of ants!

Being a bit mathematical, Bessie started wondering. Bessie noted that the hive has T (1 <= T <= 1,000) families of ants which she labeled 1..T (A ants altogether). Each family had some number Ni (1 <= Ni <= 100) of ants.

How many groups of sizes S, S+1, ..., B (1 <= S <= B <= A) can be formed?

While observing one group, the set of three ant families was seen as {1, 1, 2, 2, 3}, though rarely in that order. The possible sets of marching ants were:

3 sets with 1 ant: {1} {2} {3}
5 sets with 2 ants: {1,1} {1,2} {1,3} {2,2} {2,3}
5 sets with 3 ants: {1,1,2} {1,1,3} {1,2,2} {1,2,3} {2,2,3}
3 sets with 4 ants: {1,2,2,3} {1,1,2,2} {1,1,2,3}
1 set with 5 ants: {1,1,2,2,3}

Your job is to count the number of possible sets of ants given the data above.
 

 

Input
* Line 1: 4 space-separated integers: T, A, S, and B <br> <br>* Lines 2..A+1: Each line contains a single integer that is an ant type present in the hive
 

 

Output
* Line 1: The number of sets of size S..B (inclusive) that can be created. A set like {1,2} is the same as the set {2,1} and should not be double-counted. Print only the LAST SIX DIGITS of this number, with no leading zeroes or spaces.
 

 

Sample Input
3 5 2 3 1 2 2 1 3
 

 

Sample Output
10
 

分析:

多重集组合数也是由多重背包问题拓展出来的一类经典问题。这里仍然给大家讲2种方法:

①朴素方法:

状态:dp[i][j]:前i种中选j个可以组成的种数

决策:第i种选k个,k<=ant[i] && j-k>=0

转移:dp[i][j]=Σdp[i-1][j-k]

复杂度为O(B*Σant[i])即O(B*A)也即O(A^2),虽说这题A最大可到1e5,但是实际数据水,能过

 

②优化递推式

状态:dp[i][j]:前i种中选j个可以组成的种数

决策:第i种不选或者至少选一个

转移:

1.若不选,显然为dp[i-1][j]

2.若至少选一种,那么为dp[i][j-1]-dp[i-1][j-ant[i]-1]

我们这样来理解,dp[i][j-1] 理解为已经选了第i种一个,至于还选不选这里我们不管它,所以它可以用来代表至少选一个

但是dp[i][j-1]还有一层含义便是前i种中选j-1个可以组成的种数,所以它包含了选ant[i]个第i种,即dp[i-1][j-ant[i]-1],但

dp[i][j] 最多选ant[i]个第i种,所以最后要减去这一种。

所以 dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-ant[i]-1]

复杂度为O(T*B)

 1 #include <iostream>
 2 #include <cstring>
 3 #include <string>
 4 #include <algorithm>
 5 using namespace std;
 6 const int mod = 1000000;
 7 int dp[1005][100005];
 8 int main()
 9 {
10     int ant[1005];
11     int t, a, s, b;
12     cin >> t >> a >> s >> b;
13     memset(ant, 0, sizeof(ant));
14     int i;
15     int j;
16     for (i = 1; i <= a; i++)
17     {
18         cin >> j;
19         ant[j]++;
20     }
21     for (i = 0; i <= t; i++) dp[i][0] = 1;
22     dp[0][0] = dp[1][0] = 1;
23     for (i = 1; i <= t; i++)
24     {
25         for (j = 1; j <= b; j++)
26         {
27             if (j - ant[i] - 1 >= 0)
28             {//在取模时若出现了减法运算则需要先+Mod再对Mod取模,防止出现负数(如5%4-3%4为负数)  
29                 dp[i][j] = (dp[i - 1][j] + dp[i ][j - 1] - dp[i - 1][j - ant[i] - 1] + mod) % mod;
30             }
31             else
32             {
33                 dp[i][j] = (dp[i - 1][j] + dp[i][j - 1])%mod;
34             }     
35         }
36     }
37     int sum = 0;
38     for (i = s; i <= b; i++)
39         sum = (sum + dp[t][i]) % mod;
40     cout << sum << endl;
41     return 0;
42 }
View Code

为了节约空间%2;

#include<iostream>  
using namespace std;  
#define MOD 1000000  
int T, A, S, B;  
int ant[1005];  
int dp[2][100000];  
int ans;  
int main()  
{  
    scanf("%d%d%d%d", &T, &A, &S, &B);  
    for (int i = 1; i <= A; i++)  
    {  
        int aa;  
        scanf("%d", &aa);  
        ant[aa]++;  
    }  
    dp[0][0] = dp[1][0] = 1;  
    for (int i = 1; i <= T; i++)  
        for (int j = 1; j <= B; j++)  
            if (j - ant[i] - 1 >= 0) dp[i % 2][j] = (dp[(i - 1) % 2][j] + dp[i % 2][j - 1] - dp[(i - 1) % 2][j - ant[i] - 1] + MOD) % MOD;      //在取模时若出现了减法运算则需要先+Mod再对Mod取模,防止出现负数(如5%4-3%4为负数)  
            else dp[i % 2][j] = (dp[(i - 1) % 2][j] + dp[i % 2][j - 1]) % MOD;  
    for (int i = S; i <= B; i++)  
        ans = (ans + dp[T % 2][i]) % MOD;  
    printf("%d
", ans);  
    return 0;  
}  
View Code