定义状态为前i种蚂蚁能够形成大小为j的集合的种数, n[i]表示第i种蚂蚁有多少个
注意到每次都要求一段dp数字的和,我们可以使用一个前缀数组sum。
由于sum数组的使用,我们可以在O(1)的时间内算出dp(i, j)
同时注意到dp(i, j)只和dp(i - 1, j)有关系,所以我们可以用滚动数组来实现。
最后复杂度为O(T * A)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX_N 10005
using namespace std;
typedef long long int ll;
ll dp[MAX_N];
int main()
{
//freopen("1.txt", "r", stdin);
ll T, A, S, B, N, n[MAX_N], ant[MAX_N];
while (cin >> T >> A >> S >> B)
{
memset(ant, 0, sizeof(ant));
for (ll i = 0; i < A; i++)
scanf("%I64d", &ant[i]);
sort(ant, ant + A);
N = 0;
ll cnt = 0;
for (ll i = 0; i < A; i++)
{
cnt++;
if (ant[i] != ant[i + 1])
{
n[++N] = cnt;
cnt = 0;
}
}
ll sum[MAX_N];
memset(dp, 0, sizeof(dp));
memset(sum, 0, sizeof(sum));
for (ll i = 0; i <= B; i++)
{
dp[i] = (i <= n[1]) ? 1 : 0;
sum[i] = i > 0 ? sum[i - 1] + dp[i] : 1;
}
for (ll i = 2; i <= T; i++)
{
for (ll j = 0; j <= B; j++)
{
if (j - n[i] >= 1)
dp[j] = sum[j] - sum[j - n[i] - 1];
else
dp[j] = sum[j] - sum[0] + 1;
dp[j] %= 1000000;
}
for (ll j = 0; j <= B; j++)
sum[j] = j > 0 ? sum[j - 1] + dp[j] : dp[j];
}
ll ans = 0;
for (ll i = S; i <= B; i++)
ans = (ans + dp[i]) % 1000000;
printf("%I64d\n", ans);
}
return 0;
}