POJ_3046_Ant_Counting_(动态规划,多重集组合数)
描述
http://poj.org/problem?id=3046
n种蚂蚁,第i种有ai个,不同种类的蚂蚁可以相互区分,但同一种类的蚂蚁不能相互区分,从这些蚂蚁中取出s,s+1,s+2,...,b-1,b个,问每种取的方式的取法数之和.
原型:多重集组合数:
n种物品,第i种有ai个.不同种类的物品可以相互区分,但同一种类的物品不能相互区分.从这些物品中取出m个,有多少种取法?
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 4358 | Accepted: 1689 |
Description
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
* Lines 2..A+1: Each line contains a single integer that is an ant type present in the hive
Output
Sample Input
3 5 2 3 1 2 2 1 3
Sample Output
10
Hint
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
分析
一.原型算法:
用dp[i][j]表示在前i种物品中取出j个的组合数.
那么可以从前(i-1)个中取(j-k)个,再从第i个中取k个,则有:
dp[i][j]=Σdp[i-1][j-k](0<=k<=min(a[i],j)).枚举i,j,k,这样的算法是O(n*m^2)的.
优化:
对Σdp[i-1][j-k](0<=k<=min(a[i],j))进行变形:
讨论a[i]与j的关系:
1.a[i]<j即min(a[i],j)=a[i]
则有:Σdp[i-1][j-k](0<=k<=min(a[i],j))=Σdp[i-1][j-1-k](0<=k<=min(a[i],j-1))+dp[i-1][j]-dp[i][j-1-a[i]].
即:dp[i][j]=dp[i-1][j]+dp[i][j-1]+dp[i-1][j-1-a[i]];
2.a[i]>=j即min(a[i],j)=j
则有:Σdp[i-1][j-k](0<=k<=min(a[i],j))=Σdp[i-1][(j-1)-k](0<=k<=min(a[i],j-1))+dp[i-1][j].
即:dp[i][j]=dp[i-1][j]+dp[i][j-1].
综上:
if(j-1-a[i])>=0 dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1-a[i]]; else dp[i][j]=dp[i-1][j]+dp[i][j-1];
继续优化,在空间上,dp只用到了i和i-1,可以考虑用滚动数组重复利用空间.
二.该题:
在原型的基础上最后进行一次统计,计算ans=Σ(dp[n][i])(s<=i<=t)即可.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 5 const int maxn=1005,maxm=100*1000+5,mod=1e6; 6 int n,m,s,b; 7 int a[maxn]; 8 int dp[2][maxm]; 9 10 void solve() 11 { 12 dp[0][0]=dp[1][0]=1; 13 for(int i=1;i<=n;i++) 14 { 15 for(int j=1;j<=m;j++) 16 { 17 if(j-1-a[i]>=0) 18 { 19 dp[i&1][j]=(dp[i&1][j-1]+dp[(i-1)&1][j]-dp[(i-1)&1][j-1-a[i]]+mod)%mod; 20 } 21 else 22 { 23 dp[i&1][j]=(dp[i&1][j-1]+dp[(i-1)&1][j])%mod; 24 } 25 } 26 } 27 int ans=0; 28 for(int i=s;i<=b;i++) 29 { 30 ans=(ans+dp[n&1][i])%mod; 31 } 32 printf("%d\n",ans); 33 } 34 35 void init() 36 { 37 scanf("%d%d%d%d",&n,&m,&s,&b); 38 for(int i=1;i<=m;i++) 39 { 40 int now; 41 scanf("%d",&now); 42 a[now]++; 43 } 44 } 45 46 int main() 47 { 48 #ifndef ONLINE_JUDGE 49 freopen("ant.in","r",stdin); 50 freopen("ant.out","w",stdout); 51 #endif 52 init(); 53 solve(); 54 #ifndef ONLINE_JUDGE 55 fclose(stdin); 56 fclose(stdout); 57 system("ant.out"); 58 #endif 59 return 0; 60 }