https://vjudge.net.cn/problem/POJ-3046#author=GPT_zh
有一天,貝西在螞蟻山裏探頭探腦,看着螞蟻們來來回回地覓食。
她發現很多螞蟻都是兄弟姐妹,彼此無法區分。
她還發現,有時只有一隻螞蟻去覓食,有時幾隻,有時全部。
這就產生了大量不同組合的螞蟻!
有點數學天賦的貝茜開始琢磨起來。貝西注意到,蜂巢裏有 T(1 <= T <= 1,000)個螞蟻家庭,
她把它們標爲 1...T(共有 A 只螞蟻)。
每個家庭有一定數量的螞蟻 Ni (1 <= Ni <= 100)。
可以組成多少個大小爲 S、S+1、......、B(1 <= S <= B <= A)的小組?
在觀察一個螞蟻羣時,可以看到三個螞蟻家族的集合是{1, 1, 2, 2, 3},但很少按這個順序排列。
螞蟻行進的可能集合是
有 1 只螞蟻的 3 個集合: {1} {2} {3}
有 2 只螞蟻的 5 組 {1,1} {1,2} {1,3} {2,2} {2,3}
有 3 只螞蟻的 5 組 {1,1,2} {1,1,3} {1,2,2} {1,2,3} {2,2,3}
有 4 只螞蟻的 3 組 {1,2,2,3} {1,1,2,2} {1,1,2,3}
有 5 只螞蟻的 1 組 {1,1,2,2,3}
你的任務是根據上述數據計算可能的螞蟻集合數。
輸入
* 第 1 行:4 個空格分隔的整數: T、A、S 和 B
* 第 2...A+1 行:每行包含一個整數,即蜂巢中存在的螞蟻類型
輸出
* 第 1 行: 可創建的大小爲 S...B(包括 S...B)的集合數量。像 {1,2} 這樣的集合與 {2,1} 這樣的集合相同,不應重複計算。
只打印該數字的後六位,不打印前導零或空格。
3 5 2 3
1
2
2
1
3
10
提示
輸入細節:
三種類型的螞蟻(1...3);共有 5 只螞蟻。可以製作多少套大小爲 2 或 3 的螞蟻?
輸出細節:
5 組有兩名成員的螞蟻;另外 5 組有三名成員的螞蟻
題意簡化一下 就是
1到t組,每組抽出若干數字,總個數爲sum的方案數是多少
最後輸出 ans
ans = sum=S方案數 + sum=S+1方案數 + sum=S+2方案數 ~~~~ + sum=B方案數
解答
dp
代碼如下:
#include <iostream>
using namespace std;
const int N = 1000 * 100 + 10;
int dp[1000][N];
int ants[N];
int T, S, A, B;
const int MOD = 1000000;
void solve() {
dp[0][0] = 1;
for (int i = 1; i <= T; i++) {
for (int j = 0; j <= A; j++) {
for (int k = 0; k <= ants[i]; k++) {
if (j >= k) {
dp[i][j] += dp[i - 1][j - k];
dp[i][j] %= MOD;
}
}
}
}
long long ans = 0;
for (int i = S; i <= B; i++) {
ans += dp[T][i];
ans %= MOD;
}
cout << ans << endl;
return;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> T >> A >> S >> B;
for (int i = 1; i <= A; i++) {
int t; cin >> t;
ants[t]++;
}
solve();
return 0;
}
在POJ能ac 但是可能是數據太弱的原因。
A在極端取值 1000組螞蟻 每個螞蟻都是100個。 那麼A=100000
上面的代碼 耗時就是O(A*T*100) 就是1e10 會超時的。
下面進行優化
#include <iostream>
using namespace std;
const int N = 1000 * 100 + 10;
int dp[1000][N];
int ants[N];
int T, S, A, B;
const int MOD = 1000000;
void solve() {
dp[0][0] = 1;
for (int i = 1; i <= T; i++) {
for (int j = 0; j <= A; j++) {
if (j == 0) { dp[i][j] = 1; }
else if (j >= ants[i]+1) {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - ants[i]-1];
}
else {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
dp[i][j] %= MOD;
}
}
long long ans = 0;
for (int i = S; i <= B; i++) {
ans += dp[T][i];
ans = (ans + MOD) % MOD;
}
cout << ans << endl;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> T >> A >> S >> B;
for (int i = 1; i <= A; i++) {
int t; cin >> t;
ants[t]++;
}
solve();
return 0;
}