Flower Shop
Problem Statement There are F flowers and V vases in a row (F V). Each flower i has a preference value pref[i][j] for vase j. Flowers must be placed in strictly increasing vase order: v_1 < v_2 < < v_F. Maximize the t...
Problem Statement
Rendered from the "Problem Statement" section in the LaTeX write-up.
There are $F$ flowers and $V$ vases in a row ($F \le V$). Each flower $i$ has a preference value $\mathrm{pref}[i][j]$ for vase $j$. Flowers must be placed in strictly increasing vase order: $v_1 < v_2 < \cdots < v_F$. Maximize the total preference and output the assignment.
Editorial
The solution write-up is rendered from the LaTeX source, with equations kept live through MathJax.
Solution Approach
DP Formulation
Define: \[ \mathrm{dp}[i][j] = \max \text{ total preference placing flowers } 1, \ldots, i \text{ with flower } i \text{ in vase } j. \]
Base case: $\mathrm{dp}[1][j] = \mathrm{pref}[1][j]$ for $1 \le j \le V - F + 1$.
Transition: \[ \mathrm{dp}[i][j] = \max_{k < j} \mathrm{dp}[i{-}1][k] + \mathrm{pref}[i][j], \quad i \le j \le V - F + i. \]
Running Maximum Optimization
Rather than iterating over all $k < j$ for each $(i, j)$, we maintain a running maximum of $\mathrm{dp}[i{-}1][k]$ as $j$ increases. This reduces the time per flower from $O(V^2)$ to $O(V)$.
Reconstruction
Store the vase $k$ achieving the maximum in a parent array and trace backward from the optimal final assignment.
C++ Solution
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
int F, V;
scanf("%d %d", &F, &V);
vector<vector<int>> pref(F + 1, vector<int>(V + 1));
for (int i = 1; i <= F; i++)
for (int j = 1; j <= V; j++)
scanf("%d", &pref[i][j]);
const int NEG_INF = -1000000000;
vector<vector<int>> dp(F + 1, vector<int>(V + 1, NEG_INF));
vector<vector<int>> par(F + 1, vector<int>(V + 1, 0));
// Base case: flower 1
for (int j = 1; j <= V - F + 1; j++)
dp[1][j] = pref[1][j];
// Fill DP with running maximum
for (int i = 2; i <= F; i++) {
int best = NEG_INF;
int bestk = 0;
for (int j = i; j <= V - F + i; j++) {
// Update running max from dp[i-1][j-1]
if (dp[i - 1][j - 1] > best) {
best = dp[i - 1][j - 1];
bestk = j - 1;
}
if (best > NEG_INF) {
dp[i][j] = best + pref[i][j];
par[i][j] = bestk;
}
}
}
// Find the optimal vase for the last flower
int ans = NEG_INF, lastVase = 0;
for (int j = F; j <= V; j++) {
if (dp[F][j] > ans) {
ans = dp[F][j];
lastVase = j;
}
}
printf("%d\n", ans);
// Reconstruct the assignment
vector<int> assignment(F + 1);
assignment[F] = lastVase;
for (int i = F; i >= 2; i--)
assignment[i - 1] = par[i][assignment[i]];
for (int i = 1; i <= F; i++)
printf("%d%c", assignment[i], i < F ? ' ' : '\n');
return 0;
}
Correctness
The DP processes flowers in order $1, 2, \ldots, F$. For each flower $i$, the running maximum ensures that $\mathrm{dp}[i][j]$ considers all valid predecessor vases $k < j$. The constraint $i \le j \le V - F + i$ ensures that enough vases remain for subsequent flowers.
Complexity Analysis
Time complexity: $O(F \times V)$. Each flower iterates over at most $V$ vases, and the running maximum makes each iteration $O(1)$.
Space complexity: $O(F \times V)$ for the DP and parent tables.
Code
C++ solution used for this page.
// IOI 1999 - Flower Shop
// Place F flowers into V vases (F <= V) in strictly increasing vase order
// to maximize total preference. Output max preference and assignment.
// Approach: DP with running max optimization, O(F*V) time, O(F*V) space.
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int F, V;
cin >> F >> V;
vector<vector<int>> pref(F + 1, vector<int>(V + 1));
for (int i = 1; i <= F; i++)
for (int j = 1; j <= V; j++)
cin >> pref[i][j];
const int NEG_INF = -1e9;
// dp[i][j] = best total placing flowers 1..i with flower i in vase j
vector<vector<int>> dp(F + 1, vector<int>(V + 1, NEG_INF));
vector<vector<int>> par(F + 1, vector<int>(V + 1, 0));
// Base case: flower 1 can go in vases 1..V-F+1
for (int j = 1; j <= V - F + 1; j++) {
dp[1][j] = pref[1][j];
}
// Fill DP with running max over dp[i-1][k] for k < j
for (int i = 2; i <= F; i++) {
int best = NEG_INF;
int bestk = 0;
for (int j = i; j <= V - F + i; j++) {
// Update running max from dp[i-1][j-1]
if (dp[i - 1][j - 1] > best) {
best = dp[i - 1][j - 1];
bestk = j - 1;
}
if (best > NEG_INF) {
dp[i][j] = best + pref[i][j];
par[i][j] = bestk;
}
}
}
// Find best answer among all valid ending vases
int ans = NEG_INF, lastVase = 0;
for (int j = F; j <= V; j++) {
if (dp[F][j] > ans) {
ans = dp[F][j];
lastVase = j;
}
}
if (ans <= NEG_INF) {
cout << -1 << "\n";
return 0;
}
cout << ans << "\n";
// Reconstruct assignment
vector<int> assignment(F + 1);
assignment[F] = lastVase;
for (int i = F; i >= 2; i--) {
assignment[i - 1] = par[i][assignment[i]];
}
for (int i = 1; i <= F; i++) {
cout << assignment[i] << (i < F ? ' ' : '\n');
}
return 0;
}
Source Files and Assets
Raw files are still available here when you want the original TeX, C++, or statement assets.