Red-Black Pepper (Codeforces 1728E)
Tags: Greedy, number theory

Monocarp is going to host a party for his friends. He prepared $$$n$$$ dishes and is about to serve them. First, he has to add some powdered pepper to each of them — otherwise, the dishes will be pretty tasteless.The $$$i$$$-th dish has two values $$$a_i$$$ and $$$b_i$$$ — its tastiness with red pepper added or black pepper added, respectively. Monocarp won't add both peppers to any dish, won't add any pepper multiple times, and won't leave any dish without the pepper added.Before adding the pepper, Monocarp should first purchase the said pepper in some shop. There are $$$m$$$ shops in his local area. The $$$j$$$-th of them has packages of red pepper sufficient for $$$x_j$$$ servings and packages of black pepper sufficient for $$$y_j$$$ servings.Monocarp goes to exactly one shop, purchases multiple (possibly, zero) packages of each pepper in such a way that each dish will get the pepper added once, and no pepper is left. More formally, if he purchases $$$x$$$ red pepper packages and $$$y$$$ black pepper packages, then $$$x$$$ and $$$y$$$ should be non-negative and $$$x \cdot x_j + y \cdot y_j$$$ should be equal to $$$n$$$.For each shop, determine the maximum total tastiness of the dishes after Monocarp buys pepper packages only in this shop and adds the pepper to the dishes. If it's impossible to purchase the packages in the said way, print -1.

Input: The first line contains a single integer $$$n$$$ ($$$1 \le n \le 3 \cdot 10^5$$$) — the number of dishes.The $$$i$$$-th of the next $$$n$$$ lines contains two integers $$$a_i$$$ and $$$b_i$$$ ($$$1 \le a_i, b_i \le 10^9$$$) — the tastiness of the $$$i$$$-th dish with red pepper added or black pepper added, respectively.The next line contains a single integer $$$m$$$ ($$$1 \le m \le 3 \cdot 10^5$$$) — the number of shops.The $$$j$$$-th of the next $$$m$$$ lines contains two integers $$$x_j$$$ and $$$y_j$$$ ($$$1 \le x_j, y_j \le n$$$) — the number of servings the red and the black pepper packages are sufficient for in the $$$j$$$-th shop, respectively.

Output: Print $$$m$$$ integers. For each shop, print the maximum total tastiness of the dishes after Monocarp buys pepper packages only in this shop and adds the pepper to the dishes. If it's impossible to purchase the packages so that each dish will get the pepper added once and no pepper is left, print -1.

Note: Consider the first example.In the first shop, Monocarp can only buy $$$0$$$ red pepper packages and $$$1$$$ black pepper package. Black pepper added to all dishes will sum up to $$$10 + 50 + 2 = 62$$$.In the second shop, Monocarp can buy any number of red and black pepper packages: $$$0$$$ and $$$3$$$, $$$1$$$ and $$$2$$$, $$$2$$$ and $$$1$$$ or $$$3$$$ and $$$0$$$. The optimal choice turns out to be either $$$1$$$ and $$$2$$$ or $$$2$$$ and $$$1$$$. Monocarp can add black pepper to the first dish, red pepper to the second dish and any pepper to the third dish, the total is $$$10 + 100 + 2 = 112$$$.In the third shop, Monocarp can only buy $$$1$$$ red pepper package and $$$0$$$ black pepper packages. Red pepper added to all dishes will sum up to $$$5 + 100 + 2 = 107$$$.In the fourth shop, Monocarp can only buy an even total number of packages. Since $$$n$$$ is odd, it's impossible to get exactly $$$n$$$ packages. Thus, the answer is $$$-1$$$.

Sample Inputs:
3
5 10
100 50
2 2
4
2 3
1 1
3 2
2 2

10
3 1
2 3
1 1
2 1
6 3
1 4
4 3
1 3
5 3
5 4
10
8 10
9 3
1 4
2 5
8 3
3 5
1 6
7 2
6 7
3 1

Sample Outputs:
62
112
107
-1

26
-1
36
30
-1
26
34
26
-1
36

Solution (Python):
import io, os
input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline
import math
MAX = 3 * 10 ** 5 + 1
nearest = [-1] * (MAX + 1)
for i in range(2, MAX + 1):
    for j in range(i, MAX + 1, i):
        if nearest[j] < 0:
            nearest[j] = i

def getphi(num):
    output = num
    curr = num
    while curr > 1:
        p = nearest[curr]
        while curr % p == 0:
            curr = curr // p
        output -= output // p
    return output

def getminimumk(x, y, target, g, phiy):
    x = x // g
    y = y // g
    target = target // g
    ones = pow(x, phiy - 1, y)
    return ones * target % y

def main(t):
    n = int(input())
    diff = []
    totb = 0
    for _ in range(n):
        (a, b) = map(int, input().split())
        diff.append(a - b)
        totb += b
    diff.sort(reverse=True)
    res = [0] * (n + 1)
    res[0] = totb
    accu = 0
    cut = 0
    for i in range(n):
        accu += diff[i]
        res[i + 1] = accu + totb
        if res[i + 1] > res[i]:
            cut = i + 1
    q = int(input())
    for i in range(q):
        (x, y) = map(int, input().split())
        g = math.gcd(x, y)
        if n % g > 0:
            print(-1)
            continue
        left = cut // x * x
        right = n - left
        if y == g:
            ans = res[left]
            if left + x <= n:
                ans = max(ans, res[left + x])
            print(ans)
            continue
        ans = -1
        phiy = getphi(y // g)
        target = (y - right) % y
        k = getminimumk(x, y, target, g, phiy)
        if left - x * k >= 0:
            ans = max(ans, res[left - x * k])
        if left + (y // g - k) * x <= n:
            ans = max(ans, res[left - x * k + y // g * x])
        print(ans)
T = 1
t = 1
while t <= T:
    main(t)
    t += 1

Solution (Python):
import math
import sys, os, io
input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline

def lcm(a, b):
    return a * b // math.gcd(a, b)

def extgcd(a, b):
    if not b:
        return (1, 0)
    (u, v) = extgcd(b, a % b)
    (x, y) = (v, u - a // b * v)
    return (x, y)
n = int(input())
x = [0] * n
s = 0
for i in range(n):
    (a, b) = map(int, input().split())
    s += b
    x[i] = a - b
u = [s]
for i in sorted(x, reverse=True):
    u.append(u[-1] + i)
z = u.index(max(u))
m = int(input())
ans = []
for _ in range(m):
    (x, y) = map(int, input().split())
    g = math.gcd(x, y)
    if n % g:
        ans0 = -1
        ans.append(ans0)
        continue
    (x0, y0) = extgcd(x, y)
    (x0, y0) = (x0 * n // g, y0 * n // g)
    l = lcm(x, y)
    (x, y) = (x * x0, y * y0)
    if x < 0:
        c = -x // l + min(-x % l, 1)
        x += l * c
    x %= l
    c = max(z - x, 0) // l
    x += l * c
    ans0 = -1
    for i in [x, x + l]:
        if i <= n:
            ans0 = max(ans0, u[i])
    ans.append(ans0)
sys.stdout.write('\n'.join(map(str, ans)))

Solution (Python):
def extended_gcd(a, b):
    """"""
    (s, old_s) = (0, 1)
    (r, old_r) = (b, a)
    while r:
        q = old_r // r
        (old_r, r) = (r, old_r - q * r)
        (old_s, s) = (s, old_s - q * s)
    return (old_r, old_s, (old_r - old_s * a) // b if b else 0)

def solve():
    n = int(input())
    p = 0
    arr1 = []
    for i in range(n):
        (x, y) = map(int, input().split())
        p += y
        arr1.append(x - y)
    arr1.sort(reverse=True)
    arr = [0]
    for a in arr1:
        arr.append(arr[-1] + a)
    ma = max(arr)
    le = ri = -1
    for (i, a) in enumerate(arr):
        if a == ma:
            ri = i
            if le == -1:
                le = i
    ans = []
    m = int(input())
    for _ in range(m):
        (x, y) = map(int, input().split())
        (g, a, b) = extended_gcd(x, y)
        if n % g:
            ans.append(-1)
            continue
        res = -10 ** 18
        a *= n // g
        y //= g
        q = ((le + x - 1) // x - a) // y
        if 0 <= (a + q * y) * x <= n:
            res = max(res, arr[(a + q * y) * x])
        if 0 <= (a + (q - 1) * y) * x <= n:
            res = max(res, arr[(a + (q - 1) * y) * x])
        q = (ri // x - a) // y
        if 0 <= (a + q * y) * x <= n:
            res = max(res, arr[(a + q * y) * x])
        if 0 <= (a + (q + 1) * y) * x <= n:
            res = max(res, arr[(a + (q + 1) * y) * x])
        if res == -10 ** 18:
            ans.append(-1)
        else:
            ans.append(p + res)
    print('\n'.join((str(a) for a in ans)))
import sys
input = lambda : sys.stdin.readline().rstrip()
solve()