• 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
     
  • 相关阅读:
    hadoop中的序列化
    web服务端的架构演变
    网易考拉规则引擎平台架构设计与实践
    spring分布式事务学习笔记(2)
    质量评估面面观--聊一聊软件上线前的质量评估
    用script标签加载
    Windows下命令行下启动ORACLE服务
    笔记本优化八项
    C#编程总结(一)序列化
    学习之路十四:客户端调用WCF服务的几种方法小议
  • 原文地址:https://www.cnblogs.com/caiyishuai/p/13271252.html
Copyright © 2020-2023  润新知