zoukankan      html  css  js  c++  java
  • poj 3046 Ant Counting

    题目大意:
      有编号一到t的蚂蚁家族,每个家族有不同的蚂蚁数。

      问构成S只蚂蚁到构成B只蚂蚁共有多少种方式

      例如

      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} 

      

      

    Input

    * Line 1: 4 space-separated integers: T, A, S, and B

    * 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

    这道题用母函数来求解。
    所谓母函数,就是生成函数,说白了就是多项相乘,每一项分别表示每个家族里取一只,两只,三只。。。
    最后乘出的结果中,x的n次方的系数就表示构成n个蚂蚁有多少种方式
    代码如下
     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cstring>
     4 #define M 1000000
     5 int cnt[1002] = {0};
     6 int c1[100002] = {0};
     7 int c2[100002] = {0};
     8 int ans[100002] = {0};
     9 int n;
    10 
    11 void multi(int cn1, int cn2) {
    12     for(int i = 0; i <= cn1; i++) {
    13         for(int j = 0; j <= cn2; j++) {
    14             ans[i+j] = (ans[i+j] + c1[i]*c2[j])%M;
    15         }
    16     }
    17     n = cn1 + cn2;
    18 }
    19 
    20 int main(int argc, char const *argv[])
    21 {
    22     //freopen("input.txt","r",stdin);
    23     int t, s, a, b;
    24     scanf("%d %d %d %d",&t, &a, &s, &b);
    25     for(int i = 0; i < a; i++) {
    26         int tmp;
    27         scanf("%d",&tmp);
    28         cnt[tmp]++;
    29     }
    30     for(int i = 0; i <= cnt[1];i++) {
    31         ans[i] = 1;
    32     }
    33     n = cnt[1];
    34     for(int i = 2; i <= t; i++) {
    35         memset(c1, 0, sizeof(c1));
    36         memset(c2, 0, sizeof(c2));
    37         for(int j = 0; j <= n; j++) {
    38             c1[j] = ans[j];
    39         }
    40         for(int j = 0; j <= cnt[i]; j++) {
    41             c2[j] = 1;
    42         }
    43         memset(ans, 0, sizeof(ans));
    44         multi(n,cnt[i]);
    45     }
    46     int ansm = 0;
    47     for(int i = s; i <= b; i++) {
    48         ansm = (ansm + ans[i])%M;
    49     }
    50     printf("%d
    ",ansm);
    51     return 0;
    52 }

    注意,此题要求输出后六位,要mod M 

    此题也可以用动态规划法求解

    dp[i][j]表示前i个家族构成j的方法数

    那么

    dp[i][j] = dp[i-1][j-k](k..0 to min(j,c[i]));

    上面的式子可写为
    dp[i][j] = dp[i][j-1] + dp[i-1][j]-dp[i][j-1-c[i]];

    代码如下

     1 /*dp[i][j] means i to j geshu 
     2 
     3 dp[i][j] = dp[i-1][j-k](k..0 to min(j,c[i]));
     4 dp[i][j] = dp[i][j-1] + dp[i-1][j]-dp[i][j-1-c[i]];
     5     
     6 }*/
     7 
     8 
     9 #include <cstdio>
    10 #include <cstdlib>
    11 #include <cstring>
    12 #define M 1000000
    13 int cnt[1002] = {0};
    14 int dp[1002][100002] = {0};
    15 
    16 
    17 int main(int argc, char const *argv[])
    18 {
    19     freopen("input.txt","r",stdin);
    20     int t, s, a, b;
    21     scanf("%d %d %d %d",&t, &a, &s, &b);
    22     for(int i = 0; i < a; i++) {
    23         int tmp;
    24         scanf("%d",&tmp);
    25         cnt[tmp]++;
    26     }
    27 
    28     for(int i = 0; i <= t; i++) {
    29         dp[i][0] = 1;
    30     }
    31 
    32     for(int i = 0; i < t; i++) {
    33         for(int j = 1; j <= b; j++) {
    34             if(j-1-cnt[i+1] >= 0) {
    35                 dp[i+1][j] = (dp[i+1][j-1] + dp[i][j]-dp[i][j-1-cnt[i+1]] + M ) % M;
    36             }
    37             else {
    38                 dp[i+1][j]  = (dp[i+1][j-1] + dp[i][j])%M;
    39             }
    40         }
    41     }
    42     
    43     int ansm = 0;
    44     for(int i = s; i <= b; i++) {
    45         ansm = (ansm + dp[t][i] + M)%M;
    46     }
    47     printf("%d
    ",ansm);
    48     return 0;
    49 }
  • 相关阅读:
    setInterval的停止与启动
    postgresql常用
    STM32学习笔记(四) RCC外设的学习和理解
    STM32学习笔记(九) 外部中断,待机模式和事件唤醒
    STM32的优先级的理解及其使用
    基于STM32的红外遥控重点解析
    红外协议之NEC协议
    常用运放选型一览表
    运放参数解释及常用运放选型
    算放大器分析----虚短和虚断(转载)
  • 原文地址:https://www.cnblogs.com/jasonJie/p/5819766.html
Copyright © 2011-2022 走看看