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\n",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\n",ansm);
48     return 0;
49 }

 

posted @ 2016-08-29 21:40  Jason杰  阅读(338)  评论(0编辑  收藏  举报