The grass has dried up in Farmer John's pasture due to a drought. After hours of despair and contemplation, FJ comes up with the brilliant idea of purchasing corn to feed his precious cows.
FJ’s NN (1≤N≤1001≤N≤100) cows are arranged in a line such that the iith cow in line has a non-negative integer hunger level of hihi. As FJ’s cows are social animals and insist on eating together, the only way FJ can decrease the hunger levels of his cows is to select two adjacent cows ii and i+1i+1 and feed each of them a bag of corn, causing each of their hunger levels to decrease by one.
FJ wants to feed his cows until all of them have the same non-negative hunger level. Although he doesn't know his cows' exact hunger levels, he does know an upper bound on the hunger level of each cow; specifically, the hunger level hihi of the ii-th cow is at most HiHi (0≤Hi≤10000≤Hi≤1000).
Your job is to count the number of NN-tuples of hunger levels [h1,h2,…,hN][h1,h2,…,hN] that are consistent with these upper bounds such that it is possible for FJ to achieve his goal, modulo 109+7109+7.
The first line contains NN.The second line contains H1,H2,…,HNH1,H2,…,HN.
The number of NN-tuples of hunger levels modulo 109+7109+7.
3 9 11 7
241
There are (9+1)⋅(11+1)⋅(7+1)(9+1)⋅(11+1)⋅(7+1) 33-tuples hh that are consistent with HH.
One of these tuples is h=[8,10,5]h=[8,10,5]. In this case, it is possible to make all cows have equal hunger values: give two bags of corn to both cows 22 and 33, then give five bags of corn to both cows 11 and 22, resulting in each cow having a hunger level of 33.
Another one of these tuples is h=[0,1,0]h=[0,1,0]. In this case, it is impossible to make the hunger levels of the cows equal.
4 6 8 5 9
137
NN is even in even-numbered tests and odd in odd-numbered tests.
Problem credits: Arpan Banerjee and Benjamin Qi
[/hide]
(Analysis by Andi Qu, Arpan Banerjee, Benjamin Qi)
Case 1: NN is even
Note that if some starting NN-tuple can make all cows end up with hunger level xx, then it can also make all cows end up with hunger level 00 (by feeding each consecutive pair of cows xx bags of corn). So it suffices to find the number of NN-tuples that can be converted to all 00's.
If we want to check whether a specific NN-tuple can be converted to all 00's, then the following pseudocode suffices:
for (i in 2..N) { h[i] -= h[i-1] assert(h[i] >= 0) } assert(h[N] == 0)
The reasoning behind this is that if h1,…,hi−2h1,…,hi−2 are all equal to zero already, then the only way to make hi−1=0hi−1=0 is by feeding hi−1hi−1 bags of corn to each of cows i−1i−1 and ii.
Motivated by this, we can define a DP array where dp[i][j]dp[i][j] is the number of ways to choose h1…hih1…hi satisfying hk≤Hkhk≤Hk for all 1≤k≤i1≤k≤i such that after the ii-th iteration of the loop in the pseudocode above, hi=jhi=j. Then
That is, if hi−1=xhi−1=x and hi=j+x≤Hihi=j+x≤Hi before the ii-th iteration of the loop, then hi−1=0hi−1=0 and hi=jhi=j after the ii-th iteration of the loop. The final answer will be dp[N][0]dp[N][0].
A straightforward implementation of this algorithm runs in O(N(maxH)2)O(N(maxH)2) time, which is already fast enough. However, we can speed this up by using prefix sums for the transition since we are summing over a contiguous range. Specifically, define pref[i][j]=∑jx=0dp[i][x]pref[i][j]=∑x=0jdp[i][x]; then dp[i][j]=pref[i−1][Hi−j]dp[i][j]=pref[i−1][Hi−j]. This results in a runtime of O(N(maxH))O(N(maxH)).
Andi's code:
#include <iostream> #include <algorithm> #include <cstring> typedef long long ll; using namespace std; const ll MOD = 1e9 + 7; int main() { cin.tie(0)->sync_with_stdio(0); int n, h[101]; cin >> n; for (int i = 1; i <= n; i++) cin >> h[i]; ll dp[1001], pref[1001]; for (int i = 0; i <= h[1]; i++) pref[i] = i + 1; for (int i = h[1] + 1; i <= 1000; i++) pref[i] = h[1] + 1; for (int i = 2; i <= n; i++) { memset(dp, 0, sizeof dp); for (int j = 0; j <= h[i]; j++) { dp[j] = pref[h[i] - j]; if (dp[j] >= MOD) dp[j] -= MOD; } for (int j = 0; j <= 1000; j++) { pref[j] = dp[j]; if (j) pref[j] += pref[j - 1]; if (pref[j] >= MOD) pref[j] -= MOD; } } cout << pref[0]; return 0; }
Case 2: NN is odd
In this case, it is not true that if a starting NN-tuple can make all cows end up with hunger level xx, then it can also make all cows end up with hunger level 00. In fact, if a starting NN-tuple can make all cows end up with hunger level xx, then xx must be unique (as mentioned in the Bronze analysis). So it suffices to sum the number of starting NN-tuples over all final hunger levels xx satisfying 0≤x≤minH0≤x≤minH.
To count this quantity for a fixed xx, consider subtracting xx from all hihi and HiHi. Then the problem reduces to converting tuples to all 00's, which was described above.
The final time complexity for this case is maxHmaxH times that of the complexity for the previous case, or O(N(maxH)2)O(N(maxH)2).
Andi's code:
#include <iostream> #include <algorithm> #include <cstring> typedef long long ll; using namespace std; const ll MOD = 1e9 + 7; int main() { cin.tie(0)->sync_with_stdio(0); int n, h[101]; cin >> n; for (int i = 1; i <= n; i++) cin >> h[i]; int mn = *min_element(h + 1, h + n + 1); ll dp[1001], pref[1001], ans = 0; do { // on x-th iteration of loop, count number of tuples // that can make all heights equal to x-1 for (int i = 0; i <= h[1]; i++) pref[i] = i + 1; for (int i = h[1] + 1; i <= 1000; i++) pref[i] = h[1] + 1; for (int i = 2; i <= n; i++) { memset(dp, 0, sizeof dp); for (int j = 0; j <= h[i]; j++) { dp[j] = pref[h[i] - j]; if (dp[j] >= MOD) dp[j] -= MOD; } for (int j = 0; j <= 1000; j++) { pref[j] = dp[j]; if (j) pref[j] += pref[j - 1]; if (pref[j] >= MOD) pref[j] -= MOD; } } ans += pref[0]; if (ans >= MOD) ans -= MOD; for (int i = 1; i <= n; i++) h[i]--; } while (n % 2 && mn--); cout << ans; return 0; }
Interestingly, each DP transition is equivalent to reversing a subarray of the previous prefix sum array, so we can code a very short (and fast) solution using functions from C++'s standard library.
#include <algorithm> #include <cstdio> #include <numeric> using namespace std; int mod_add(int x, int y) { int res = x + y; if (res >= 1000000007) res -= 1000000007; return res; } int main() { int n, h[101], mn, mx, dp[1001], ans = 0; scanf("%d", &n); for (int i = 0; i < n; i++) scanf("%d", h + i); mn = *min_element(h, h + n), mx = *max_element(h, h + n); do { fill(dp, dp + mx + 1, 1); for (int i = 0; i < n; i++) { reverse(dp, dp + h[i] + 1); fill(dp + h[i] + 1, dp + mx + 1, 0); partial_sum(dp, dp + mx + 1, dp, mod_add); } ans = mod_add(ans, dp[0]); for (int i = 0; i < n; i++) h[i]--; } while (n % 2 && mn-- && mx--); printf("%d\n", ans); return 0; }
[/hide]
翰林课程体验,退费流程快速投诉邮箱: yuxi@linstitute.net 沪ICP备2023009024号-1