• 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
     
  • 相关阅读:
    文件上传案例_Socket_测试
    Linux的小整理(入门)
    full stack 第一天
    基础考题 试题
    shell语法
    网络管理
    图像类
    定时储存
    网络管理
    磁盘管理
  • 原文地址:https://www.cnblogs.com/caiyishuai/p/13271252.html
Copyright © 2020-2023  润新知