Ant Counting
题目描述: 有一天,贝茜无聊地坐在蚂蚁洞前看蚂蚁们进进出出地搬运食物.很快贝茜发现有些蚂蚁长得几乎一模一样,于是她认为那些蚂蚁是兄弟,也就是说它们是同一个家族里的成员.她也发现整个蚂蚁群里有时只有一只出来觅食,有时是几只,有时干脆整个蚁群一起出来.这样一来,蚂蚁们出行觅食时的组队方案就有很多种.作为一头有数学头脑的奶牛,贝茜注意到整个蚂蚁群由T(1≤T≤1000)个家族组成,她将这些家族按1到T依次编号.编号为i的家族里有Ni(1≤Ni≤100)只蚂蚁.同一个家族里的蚂蚁可以认为是完全相同的.
如果一共有S,S+1….,B(1≤S≤B≤A)只蚂蚁一起出去觅食,它们一共能组成多少种不同的队伍呢?注意:只要两支队伍中所包含某个家族的蚂蚁数不同,我们就认为这两支队伍不同.由于贝茜无法分辨出同一家族的蚂蚁,所以当两支队伍中所包含的所有家族的蚂蚁数都相同时,即使有某个家族换了几只蚂蚁出来,贝茜也会因为看不出不同而把它们认为是同一支队伍.
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}
*第1行:可以创建的大小为S…B(包括)的集合数。 像{1,2}这样的集合与集合{2,1}相同,不应重复计算。 仅打印此数字的最后六位数,不带前导零或空格。
思路分析:
我们先分析核心代码的来处:
f[i][j]=从前i种物品中选取j个物品的组合总数。
为了从前i种物品中选取j个,我们可以先从前i-1种物品中选取j-k个,然后在从第i个物品中补上剩下的k个
所以可以得到以下递推关系:
当j>a[i]时(j-1-a[i]>=0):
f[i][j]=f[i−1][j]+f[i−1][j−1]+…+f[i−1][j−ai]f[i][j]=f[i−1][j]+f[i−1][j−1]+…+f[i−1][j−ai] ,;
我们求 f[i][j] 的时候可以使用 f[i][j−1] 计算过的值,避免重复枚举 k.
f[i][j−1]=f[i−1][j−1]+…+f[i−1][j−ai−1];
根据上个式子我们可以得到:
f[i][j]=f[i][j−1]+f[i−1][j]−f[i−1][j−ai−1];
那么我们该怎么理解上述的式子呢?
1.不选选第i种:f[i-1][j];就是在前i-1种里面选择j个;
2.选择第i种 :f[i][j-1]-f[i-1][j-a[i]-1];
我们可以这样理解选择的情况:f[i][j-1]我们可以认为是选择了第i种1个,至于后面我们还选不选第i种我们先不管。f[i][j-1]是在前i种选择j-1个可组成的种数,那么它包含了选a[i]个第i种的情况,即f[i-1][j-a[i]-1],但是f[i][j]最多也就是拿x[i]项,所以要在这里减去f[i-1][j-a[i]-1];
当j<=a[i]时:
f[i][j]=f[i−1][j]+f[i−1][j−1]+…+f[i−1][0];
f[i][j-1] = f[i−1][j−1]+…+f[i−1][0];
由上面的两个式子可知:
f[i][j] = f[i-1][j]+f[i][j-1];
此处分析和上面的差不多,只是不可能存在第i种都取的情况;
#include<cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define Maxn 1000
#define Maxm 100
#define Mod 1000000
int num[Maxn + 5], f[Maxn + 5][Maxn * Maxm + 5];
int main() {
int t, a, s, b, ans = 0;
scanf("%d %d %d %d", &t, &a, &s, &b);
for (int i = 1; i <= a; i++) { //存储每种的数量
int x;
scanf("%d", &x);
num[x]++;
}
for (int i = 0; i <= t; i++)
f[i][0] = 1; //取0都会是一种
for (int i = 1; i <= a; i++) {
for (int j = 1; j <= t; j++) {
if (j - 1 - num[i] >= 0)
f[i][j] = (f[i - 1][j] + f[i][j - 1] - f[i-1][j - 1 - num[i]] + Mod) % Mod;
else
f[i][j] = (f[i - 1][j] + f[i][j - 1])%Mod;
}
}
for (int i = s; i <= b; i++){
ans += f[t][i];
ans%=Mod;
}
printf("%d\n", ans);
return 0;
}