Processing math: 100%
(Analysis by Benjamin Qi, Brandon Wang, Claire Zhang)

Let us first suppose we compute each en separately, and then we will do this D times. (Later we will describe how to support updates.) Suppose (m1,b1),,(mn,bn) are in increasing order of mi. We can make the following observations:

  1. If bibj for i<j, then we can ignore demand j.
  2. Let us suppose we create ai tasks on day i. Then, we can assume a1a2a3 (since if ai<aj with i>j, we can swap ai and aj).

Subtask 1 (D100, mi100):

Let the cost of a sequence of increments (ai) be the energy required (i3ai). Additionally, say (ai) is valid if it satisfies all demands.

Claim: The lexicographically minimal sequence (ai) which is non-increasing and valid attains minimum cost.

Proof: Let (ai) be the lexicographically minimal sequence which is non-increasing and valid. Suppose for sake of contradiction that the lowest-cost non-increasing, valid sequence (bi) has lower cost than (ai). Without loss of generality, say the first index i where aibi is i=1. For example, consider

(ai)=[4,4,4,4,2]

(bi)=[5,5,4,3,1]

Then we claim (bi) is not the lowest-cost sequence which is non-increasing and valid: consider decrementing bj, where j is maximum index such that bj=b1, and incrementing bk, where k is the minimum index such that bkb12 (if such exists). In the example,

(bi)=[5,5,4,3,1](bi)=[5,51,4,3+1,2]

(bi)

(bi) is a valid, non-increasing, sequence with lower cost than (bi)-- a contradiction. (end of proof)

Using this claim, we can greedily select the smallest ai for i=1,,D. If there are 0 test cases on day 0 and at least bi on day mi, there must be a day 1jmi where bimi test cases are prepared (max 1-day increase is at least average increase). a1 is the maximum ai, so a1 must be at least maxDi=1bimi. Let a1=maxDi=1bimi and decrement all mi. If we set all ai in this manner, (ai) is

Therefore, this greedy algorithm (code below) attains the lex. min valid sequence, which we have shown is cost-optimal. Its time complexity is O(D3+D2log(B)).

def ceildiv(a, b):
    return -(a // -b)


def solve(demands):
    MOD = 10**9 + 7
    ans = 0
    while len(demands) > 0:
        a1 = max(ceildiv(b, m) for m, b in demands)
        demands = [(m - 1, b - a1) for m, b in demands if b > a1]
        ans = (ans + pow(3, a1 - 1, MOD)) % MOD
    return ans


D = int(input())

demands = []
for _ in range(D):
    m, b = map(int, input().split())
    demands.append((m, b))
    print(solve(demands))

Subtask 2 (D3000):

Observation 2 implies that we only need to satisfy (mi,bi) that are on the "upper left" hull of the demand set (where we assume (0,0) is also a demand). Let's take some (a1,a2,) that satisfies everything on the upper left hull. We claim that we can "massage" the ai so that each (mi,bi) on the upper left hull is exactly satisfied. We will also do this in a way so that if (mi,bi), (mj,bj) are consecutive on the hull, then ami+1ai+2amj still holds (so everything not on the hull is still automatically satisfied). To see how to do this, suppose a1+a2++ami>bi with i minimal, and let j>i be minimal such that a1+a2++amj=bj (also, i,j are both on the hull). Then, we have ami1+1++ami>bibi1, but amj1++amj<bjbj1. By convexity, we must have bibi1mimi1bjbj1mjmj1, so we have ami1+1>amj. We can then move 1 test-case from the last ak=ami1+1 (with mi1+1kmi) to the first a=amj (with mj1+1mj). In this way, we have moved a subtask from a day with ak subtasks to a day with a<ak subtasks, which does not increase the total cost.

The point of this argument is as follows: Suppose (0,0),(mi1,bi1),,(mik,bik) is the upper left hull. Then, we can assume Bessie has prepared exactly bit test-cases by day mit. In particular, between days mit1+1 and mit (inclusive), Bessie prepares bitbit1 test cases. By convexity of 3a1, we want the number of test cases per day to be as close together as possible, so we should have them all be either x or x, x being the average number of test cases prepared in this interval.

This gives us an O(D2(logD+logB)) solution (code below).

#include <algorithm>
#include <iostream>
#include <stack>
 
typedef long long ll;
typedef std::pair<ll,ll> pi;
 
const int MAXN = 2e5+5;
const ll P = 1000000007;
 
int N;
pi p[MAXN];
 
ll modexp (ll a, ll n) {
	if (n == 0) return 1;
	ll b = modexp((a*a)%P, n/2);
	return (n%2?(a*b)%P:b);
}
 
void input () {
	std::cin >> N;
	for (int i = 0; i < N; i++) {
		std::cin >> p[i].first >> p[i].second;
	}
}
 
bool pre (pi p, pi q) {
	// returns true if line to p is on or below line to q
	return p.second*q.first <= q.second*p.first;
}
 
ll diff (pi p, pi q) {
	ll dy = q.second - p.second;
	ll dx = q.first - p.first;
	ll nh = dy%dx%P;
	ll lo = dy/dx;
	if (lo == 0) {
		return ((nh%P) * modexp(3, lo))%P;
	}
	return (modexp(3, lo-1)*((dx-nh)%P) + modexp(3, lo)*(nh%P))%P;
}
 
ll query (int M) {
	std::sort(p, p+M);
	std::stack<pi> stk;
	stk.push({0, 0});
	for (int i = 0; i < M; i++) {
		while (int(stk.size()) > 1) {
			pi q = stk.top();
			stk.pop();
			pi r = stk.top();
			if (pre({q.first-r.first, q.second-r.second}, {p[i].first-r.first, p[i].second-r.second})) {
				continue;
			}
			else {
				stk.push(q);
				break;
			}
		}
		if (stk.top().second < p[i].second) {
			stk.push(p[i]);
		}
	}	
	ll ans = 0;
	pi cur = stk.top();
	stk.pop();
	while (!stk.empty()) {
		ans = (ans + diff(stk.top(), cur))%P;
		cur = stk.top();
		stk.pop();
	}
	return ans;
}
 
int main () {
	input();
	for (int i = 1; i <= N; i++) {
		std::cout << query(i) << "\n";
	}
}

Subtask 3 (D2105):

To optimize, we need to efficiently maintain consecutive pairs of points on the hull as points are added. For two sets of points A, B, h(AB)=h(h(A),h(B)), where h(S) denotes the convex hull of S, a set of 2d points. This means that a point that's not on the convex hull will never be after new points are added. Thus, inserting a new point inserts at most 1 new point to the hull and deletes possibly many.

We can maintain a set of (x,y) points on the hull, sorted by x (and y). Updating the convex hull after inserting a point p could require removing a ball of points around p. Say p has index i in the sorted set. We can repeatedly check if i(i+1)(i+2) forms a left turn; if so, i+1 does not belong on the hull. Similarly, check for right turns of the form (i2)(i1)i.

Note that ais should never be negative, so we should remove i+1 whenever i(i+1) is downward sloping. Each point is removed at most once in O(logD) time, and exponentiating to calculate the costs involving it is O(logB) per hull edge. The total work is O(D(logD+logB)).

Code:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

template <ll Mod>
struct ModInt {
  ll n;

  ModInt(const ll x = 0) : n(x) {
    while (n < 0) n += Mod;
    n %= Mod;
  }
  explicit operator int() const { return n; }
  inline ModInt operator+(const ModInt r) const noexcept { return ModInt(*this) += r; }
  inline ModInt operator-(const ModInt r) const noexcept { return ModInt(*this) -= r; }
  inline ModInt operator*(const ModInt r) const noexcept { return ModInt(*this) *= r; }
  inline ModInt operator/(const ModInt r) const noexcept { return ModInt(*this) /= r; }
  inline ModInt &operator+=(const ModInt r) noexcept {
    n += r.n;
    if (n >= Mod) n -= Mod;
    return *this;
  }
  inline ModInt &operator-=(const ModInt r) noexcept {
    if (n < r.n) n += Mod;
    n -= r.n;
    return *this;
  }
  inline ModInt &operator*=(const ModInt r) noexcept {
    n = n * r.n % Mod;
    return *this;
  }
  inline ModInt &operator/=(const ModInt r) noexcept { return *this *= r.inv(); }

  inline ModInt pow(ll x) const noexcept {
    ModInt<Mod> ret(1), tmp(*this);
    while (x) {
      if (x&1) ret *= tmp;
      tmp *= tmp;
      x >>= 1;
    }
    return ret;
  }
  inline ModInt inv() const noexcept { return pow(Mod-2); }

  friend ostream& operator<<(ostream& os, const ModInt& obj) { return os << obj.n; }
  friend istream& operator>>(istream& is, ModInt& obj) {
    ll t;
    is >> t;
    obj = ModInt(t);
    return is;
  }
};

const ll mod = 1000000007;
using mi = ModInt<mod>;


int main(){
    cin.tie(0)->sync_with_stdio(0);

    int D; cin >> D;

    mi ans=0;

    map<int, ll> ys;
    set<int> xs({0});

    auto left_turn=[&](int x1, int x2, int x3)->bool{
        return (ys[x2]-ys[x1])*(x3-x2) <= (ys[x3]-ys[x2])*(x2-x1);
    };

    auto right_turn=[&](int x1, int x2, int x3)->bool{
        return !left_turn(x1, x2, x3);
    };

    auto f=[&](int x1, int x2)->mi{
        int dx = x2 - x1;
        ll dy = ys[x2] - ys[x1];
        if(dy<=0) return 0;
        // dx*k <= dy <= dx*(k+1)
        ll step = dy/dx;
        if(dy%dx) return mi(3).pow(dy/dx)*(dy%dx) + (dy/dx? mi(3).pow(dy/dx-1) : 0) *(dx-(dy%dx));
        return dy/dx? mi(3).pow(dy/dx-1)*dx : 0;
    };

    auto upd=[&](int x, bool del = 0){
        auto it = xs.lower_bound(x);
        assert(*it == x);
        assert(it != xs.begin());
        int x_bef = *prev(it);
        if(del){
            ans -= f(x_bef, x);
            it++;
            if(it != xs.end()){
                int x_af = *it;
                ans += f(x_bef, x_af) - f(x, x_af);
            }
            xs.erase(x);
            ys[x] = 0;
        } else{
            ans += f(x_bef, x);
            it++;
            if(it != xs.end()){
                int x_af = *it;
                ans += f(x, x_af) - f(x_bef, x_af);
            }
        }
    };

    auto ins=[&](int x, ll y){
        // check if x -- y -- z y is below segment (x-z) in CH -- if so return
        if(ys[x] and ys[x] >= y) return;
        if(ys[x]) upd(x, 1);
        ys[x] = y;
        xs.insert(x);
        upd(x);
        while(true){
            auto it = xs.lower_bound(x);
            bool ch = 0;
            for(int i=0; i<3; i++){
                if(it!=xs.end() and next(it)!=xs.end() and next(next(it))!=xs.end()){
                    int a=*it, b=*next(it), c=*next(next(it));
                    if(left_turn(a, b, c)){
                        ch = 1;
                        upd(b, 1);
                        break;
                    }
                }
                if(it==xs.begin()) break;
                it--;
            }
            if(!ch) break;
        }
    };

    while(D--){
        int t;
        ll b;
        cin >> t >> b;
        ins(t, b);
        cout << ans << "\n";
    }
}

Note that the solution is correct even if you divide when computing left_turn instead of multiply:

auto left_turn = [&](int x1, int x2, int x3) -> bool {
	return ys[x2] <= ys[x3] && (ys[x2] - ys[x1]) / (x2 - x1) <= (ys[x3] - ys[x2]) / (x3 - x2);
};