POJ 3046 -- Ant Counting (动态规划)

来源:互联网 发布:女朋友漂亮知乎 编辑:程序博客网 时间:2024/05/16 13:52
Ant Counting
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 6037 Accepted: 2246

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 

* 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 312213

Sample Output

10

Hint

INPUT DETAILS: 

Three types of ants (1..3); 5 ants altogether. How many sets of size 2 or size 3 can be made? 


OUTPUT DETAILS: 

5 sets of ants with two members; 5 more sets of ants with three members

Source

USACO 2005 November Silver



问题描述: 第一行给出T A S B四个整数

T是指有T种不同的数,A是指这些数的总个数

S和B是指一个区间[S,B] 这个区间的每个整数值x代表这A个数的x个元素的子集


求: 从S到B这些子集的总个数的最后6位(MOD 1000,000)

实际上这就是一个多重集组合数问题:


有n种物品,第i种物品有ai个,不同种类的物品可以互相区分而相同种类的无法区分.

从这些物品中取出m个 有多少取法


每种物品就对应每种数字,相同的数字无法区分, 从这些数字种取S....B个 取法的总数%1000,000是多少


分析:

定义 dp[i+1][j] := 从前i种数取出j个数 共有多少种取法

可以这样考虑:

                        min(A[i],j)

dp[i+1][j] = Σ  dp[i][j-k] * 1 

  k = 0

(也就是说 从前i-1种取出k个,剩下的从第i种取出,由于第i种的所有数都是相同的 无法区分 所以只有一种取法 在后面*1即可)

这样,枚举i,j,k 复杂度为O(nm²)


min(A[i],j)                 min(j-1,A[i]) 
 Σdp[i][j-k] * 1   =   Σdp[i][j-k-1] + dp[i][j](少的一项 k = 0) - dp[j-1-A[i]](多的一项 k = A[i]); 
  k=0                             k=0


那么 把i代换成i+1 j-k代换为k

就得到 dp[i+1][j]  = dp[i+1][j-1] + dp[i][j] - dp[j-1-A[i]](如果j-1 >=A[i]) 

这样复杂度为O(mn)


代码:

#include <cstdio>#include <cstring>#include <algorithm>#include <map>using namespace std;int t,a,s,b;int dp[5000 + 10][5000 + 10];int A[5000 + 10];map<int,int> m;int main(){scanf("%d %d %d %d",&t,&a,&s,&b);for(int i = 0;i<a;i++){int x;scanf("%d",&x);A[x-1]++;}//int cnt = 0;//for(map<int,int>::iterator it = m.begin();it!=m.end();it++)//{//A[cnt++] = it->second;//}for(int i = 0 ;i<=t;i++){dp[i][0] = 1;}for(int i = 0;i<t;i++){for(int j = 1;j<=b;j++){if(j - 1 - A[i] >=0){dp[i+1][j] = (dp[i+1][j-1] + dp[i][j] - dp[i][j-1-A[i]] + 1000000) % 1000000;}else{dp[i+1][j] = (dp[i+1][j-1] + dp[i][j]) % 1000000; }}}//  dp[i+1][j] 从前i种选择出j个//  min(A[i],j) min(j-1,A[i]) // = Σdp[i][j-k] * 1   =  Σdp[i][j-k-1] + dp[i][j](少的一项 k = 0) - dp[j-1-A[i]](多的一项 k = A[i]); //  k=0   k=0//主要是考虑如何降低复杂度 把Σ变为一维的加减运算 //代换    dp[i+1][j] = dp[i+1][j-1] + dp[i][j] - dp[j-1-A[i]] long long  ans = 0;for(int i = s;i<=b;i++){ans = (ans + dp[t][i]) % 1000000;} printf("%lld\n",ans);}