最小化 Array 中的变化总和,使得新元素与数组总和的比率最多为 p:q
给定一个包含n 个整数和两个整数p和q的数组A ,任务是增加数组 A中的一些(或全部)值,使得每个元素(在第一个元素之后)相对于总和的比率当前元素之前的所有元素的值仍然小于或等于p / q 。返回要完成的最小更改总和。
例子:
Input: n = 4, A = {20100, 1, 202, 202}, p = 1, q = 100
Output: 99
Explanation: 50 is added to the first element and 49 to the second element, so that the resulting array becomes {20150, 50, 202, 202}.
50/20150 <= 1/100
202/(20150+50) <=1/100
202/(20150+50+202)<=1/100
Therefore, the condition is satisfied for all the elements and hence 50+49=99 would be the answer.
There are other answers possible as well, but we need to find out the minimum possible sum.
Input: n = 3, A = {1, 1, 1}, p = 100, q = 100
Output: 0
方法:使用前缀和和二进制搜索的概念可以很容易地解决这个问题。
- It can be clearly observed that
- if the condition stated in the problem is achieved for a certain sum of changes (say S),
- then it is always possible to achieve the condition for all the numbers greater than S and
- cannot be achieved for all numbers less than S.
- So, we can apply binary search to find the answer.
- Also, it must be carefully observed that instead of distributing S(sum of changes) over different elements, if we just add it to first element, that would not affect the answer.
For example, in the first example above, if 99 is added to the first element, the resultant array will still meet the required condition.
请按照以下步骤解决问题 -
- 制作给定数组的前缀和数组。
- 在 0 到 INT_MAX 范围内使用二进制搜索找到可能的最小答案。
NOTE: Division may lead to overlapping values and errors.
So, instead of comparison like (a/b)<=(c/d), we will do (a*d)<=(b*c).
下面是上述方法的实现:
C++
// C++ program for find minimum
// sum of changes in an array
#include
using namespace std;
// function to check if the candidate sum
// satisfies the condition of the problem
bool isValid(int candidate, int pre[], int n, int A[],
int p, int q)
{
// flag variable to check wrong answer
bool flag = true;
for (int i = 1; i < n; i++) {
// Now for each element, we are checking
// if its ratio with sum of all previous
// elements + candidate is greater than p/q.
// If so, we will return false.
int curr_sum = pre[i - 1] + candidate;
if (A[i] * q > p * curr_sum) {
flag = false;
break;
}
// comparing like A[i]/(curr_sum)>p/q
// will be error prone.
}
return flag;
}
int solve(int n, int A[], int p, int q)
{
// declaring and constructing
// prefix sum array
int pre[n];
pre[0] = A[0];
for (int i = 1; i < n; i++) {
pre[i] = A[i] + pre[i - 1];
}
// setting lower and upper bound for
// binary search
int lo = 0, hi = INT_MAX, ans = INT_MAX;
// since minimum answer is needed,
// so it is initialized with INT_MAX
while (lo <= hi) {
// calculating mid by using (lo+hi)/2
// may overflow in certain cases
int mid = lo + (hi - lo) / 2;
// checking if required ratio would be
// achieved by all elements if "mid" is
// considered as answer
if (isValid(mid, pre, n, A, p, q)) {
ans = mid;
hi = mid - 1;
}
else {
lo = mid + 1;
}
}
return ans;
}
// Driver Function
int main()
{
int n, p, q;
n = 4, p = 1, q = 100;
int A[] = { 20100, 1, 202, 202 };
// printing the required answer
cout << solve(n, A, p, q) << endl;
}
Java
// Java program for find minimum
// sum of changes in an arraykage whatever //do not write package name here */
import java.io.*;
class GFG {
// function to check if the candidate sum
// satisfies the condition of the problem
static Boolean isValid(int candidate, int pre[], int n, int A[],
int p, int q)
{
// flag variable to check wrong answer
Boolean flag = true;
for (int i = 1; i < n; i++) {
// Now for each element, we are checking
// if its ratio with sum of all previous
// elements + candidate is greater than p/q.
// If so, we will return false.
int curr_sum = pre[i - 1] + candidate;
if (A[i] * q > p * curr_sum) {
flag = false;
break;
}
// comparing like A[i]/(curr_sum)>p/q
// will be error prone.
}
return flag;
}
static int solve(int n, int A[], int p, int q)
{
// declaring and constructing
// prefix sum array
int pre[] = new int[n];
pre[0] = A[0];
for (int i = 1; i < n; i++) {
pre[i] = A[i] + pre[i - 1];
}
// setting lower and upper bound for
// binary search
int lo = 0, hi = Integer.MAX_VALUE, ans = Integer.MAX_VALUE;
// since minimum answer is needed,
// so it is initialized with INT_MAX
while (lo <= hi) {
// calculating mid by using (lo+hi)/2
// may overflow in certain cases
int mid = lo + (hi - lo) / 2;
// checking if required ratio would be
// achieved by all elements if "mid" is
// considered as answer
if (isValid(mid, pre, n, A, p, q)) {
ans = mid;
hi = mid - 1;
}
else {
lo = mid + 1;
}
}
return ans;
}
// Driver Function
public static void main (String[] args)
{
int n = 4, p = 1, q = 100;
int A[] = { 20100, 1, 202, 202 };
// printing the required answer
System.out.println(solve(n, A, p, q));
}
}
// This code is contributed by hrithikgarg03188.
Python3
# Python code for the above approach
import sys
# function to check if the candidate sum
# satisfies the condition of the problem
def isValid(candidate, pre, n, A, p, q) :
# flag variable to check wrong answer
flag = True
for i in range(1, n) :
# Now for each element, we are checking
# if its ratio with sum of all previous
# elements + candidate is greater than p/q.
# If so, we will return false.
curr_sum = pre[i - 1] + candidate
if (A[i] * q > p * curr_sum) :
flag = False
break
# comparing like A[i]/(curr_sum)>p/q
# will be error prone.
return flag
def solve(n, A, p, q) :
# declaring and constructing
# prefix sum array
pre = [0] * 100
pre[0] = A[0]
for i in range(1, n) :
pre[i] = A[i] + pre[i - 1]
# setting lower and upper bound for
# binary search
lo = 0
hi = sys.maxsize
ans = sys.maxsize
# since minimum answer is needed,
# so it is initialized with INT_MAX
while (lo <= hi) :
# calculating mid by using (lo+hi)/2
# may overflow in certain cases
mid = lo + (hi - lo) // 2
# checking if required ratio would be
# achieved by all elements if "mid" is
# considered as answer
if (isValid(mid, pre, n, A, p, q)) :
ans = mid
hi = mid - 1
else :
lo = mid + 1
return ans
# Driver Function
n = 4
p = 1
q = 100
A = [ 20100, 1, 202, 202 ]
# printing the required answer
print(solve(n, A, p, q))
# This code is contributed by code_hunt.
C#
// C# program for find minimum
// sum of changes in an array
using System;
class GFG
{
// function to check if the candidate sum
// satisfies the condition of the problem
static bool isValid(int candidate, int []pre, int n, int []A,
int p, int q)
{
// flag variable to check wrong answer
bool flag = true;
for (int i = 1; i < n; i++) {
// Now for each element, we are checking
// if its ratio with sum of all previous
// elements + candidate is greater than p/q.
// If so, we will return false.
int curr_sum = pre[i - 1] + candidate;
if (A[i] * q > p * curr_sum) {
flag = false;
break;
}
// comparing like A[i]/(curr_sum)>p/q
// will be error prone.
}
return flag;
}
static int solve(int n, int []A, int p, int q)
{
// declaring and constructing
// prefix sum array
int []pre = new int[n];
pre[0] = A[0];
for (int i = 1; i < n; i++) {
pre[i] = A[i] + pre[i - 1];
}
// setting lower and upper bound for
// binary search
int lo = 0, hi = Int32.MaxValue, ans = Int32.MaxValue;
// since minimum answer is needed,
// so it is initialized with INT_MAX
while (lo <= hi) {
// calculating mid by using (lo+hi)/2
// may overflow in certain cases
int mid = lo + (hi - lo) / 2;
// checking if required ratio would be
// achieved by all elements if "mid" is
// considered as answer
if (isValid(mid, pre, n, A, p, q)) {
ans = mid;
hi = mid - 1;
}
else {
lo = mid + 1;
}
}
return ans;
}
// Driver Function
public static void Main()
{
int n = 4, p = 1, q = 100;
int []A = { 20100, 1, 202, 202 };
// printing the required answer
Console.WriteLine(solve(n, A, p, q));
}
}
// This code is contributed by Samim Hossain Mondal.
Javascript
99
时间复杂度:O(n log(INT_MAX))
辅助空间:O(n)