POI 2017 - Containers

Author: Andi Qu

Time Complexity: O((K+N)N)\mathcal O((K + N) \sqrt N).

Let's consider two naive solutions and try to combine them! (In general, this is a good idea for square-root-decomposition problems.)

Naive solution 1 - slow update; fast query

Keep an array that stores the number of containers on each position. When we process a crane, we can simply increment the positions that it puts containers on.

Querying the final answer only takes O(N)\mathcal O(N) time, but processing all of the cranes can potentially take O(KN)\mathcal O(KN) time in total.

This solution would work well if all did_i were large, as processing each crane takes O(N/di)\mathcal O(N / d_i) time.

Naive solution 2 - fast update; slow query

Let dp[x][y]dp[x][y] denote the prefix sum of the number of cranes with di=yd_i = y and xai(mody)x \equiv a_i \pmod{y}. When we process a crane, we change exactly two values in the DP array. The answer for position pp is simply

y=0max(di)xpxp(mody)dp[x][y].\sum_{y = 0}^{\max(d_i)} \sum_{x \leq p \land x \equiv p \pmod{y}}dp[x][y].

Processing all of the cranes now only takes only O(K)\mathcal O(K) time, but querying the final answer can potentially take O(NK)\mathcal O(NK) time.

This solution would work well if all did_i were small, as we querying the solution takes O(Nmax(di))\mathcal O(N \cdot \max(d_i)) time.

Model solution - fast(ish) update; fast(ish) query

When diNd_i \geq \sqrt N, then apply solution 1. Otherwise, apply solution 2.

After processing all the cranes, we can simply add the results from the two solutions.

#include <bits/stdc++.h>
#define FOR(i, x, y) for (int i = x; i < y; i++)
using namespace std;
const int sqrt_n = 300;
int containers[100001];
int dp[100001 + sqrt_n][sqrt_n];
int main() {
iostream::sync_with_stdio(false);

Join the USACO Forum!

Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!