algorithm for codeforces 559C - algorithm

I need help with a problem problem c,Although I have a solution But i want to ask If we want to minimize the sweets then
after assigning these ans += b[i] * M sweets we can now say that this is minimum number .
But after that we are assigning again here again ans += g[i] - b[N]
Here b[N] is the max number in group of boys
Please help!
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int N, M;
long long g[maxn], b[maxn];
int main() {
scanf("%d%d", &N, &M);
for(int i = 1; i <= N; i ++)
scanf("%lld", &b[i]);
for(int i = 1; i <= M; i ++) {
scanf("%lld", &g[i]);
}
sort(b + 1, b + 1 + N);
sort(g + 1, g + 1 + M);
if(b[N] > g[1]) printf("-1\n");
else {
long long ans = 0;
for(int i = N; i >= 1; i --)
ans += b[i] * M;
for(int i = 2; i <= M; i ++)
ans += g[i] - b[N];
if(g[1] != b[N]) ans += g[1] - b[N - 1];
printf("%lld\n", ans);
}
return 0;
}

First we sort the girls and boys by min given/max get sweets.
There are 3 steps then:
1 - Each boys give their minimum sweets to each girls.
for(int i = N; i >= 1; i --)
ans += b[i] * M;
boys' conditions are fulfilled.
2 - Each girls except the first one get their maximum sweets from the last boy. (Who has the largest minimum, because this way we can minimize the sweets given in this step.) But he had already given his minimum to all of the girls in the previous step, so that's why he gives only the remaining g[i]-b[N] sweets here.
Notice, he cannot add the max to the first girl too, because he needs to add his minimum to somebody.
for(int i = 2; i <= M; i ++)
ans += g[i] - b[N];
girls' conditions (except the first one) are fulfilled.
3 - somebody needs to add the maximum sweets to the first girl. The optimum solution is if the boy with the 2nd largest minimum gives them to her. But it's only needed if the first girl's maximum is greater than the lasts' boy's minimum, otherwise her condition was already fulfilled.
if(g[1] != b[N])
ans += g[1] - b[N - 1];
firs't girl's condition is fulfilled.
Maybe it's more understandable in this format:
for(int i = 1; i < N; i ++)
ans += b[i] * M;
for(int i = 2; i <= M; i ++)
ans += g[i];
ans += b[N];
if(g[1] != b[N])
ans += g[1] - b[N - 1];
... however, there are a few corner-cases which are not handled in this algorithm: What is there is only 1 boy or/and 1 girl? (But that's only a few extra if/else branches.)

Related

summary of the algorithm of K sum

It is the well-konw Twelvefold way:
https://en.wikipedia.org/wiki/Twelvefold_way
Where we want to find the number of solutions for following equation:
X1 + X2 + ... + XK = target
from the given array:
vector<int> vec(N);
We can assume vec[i] > 0. There are 3 cases, for example
vec = {1,2,3}, target = 5, K = 3.
Xi can be duplicate and solution can be duplicate.
6 solutions are {1,2,2}, {2,1,2}, {2,2,1}, {1,1,3}, {1,3,1}, {3,1,1}
Xi can be duplicate and solution cannot be duplicate.
2 solutions are {1,2,2}, {1,1,3}
Xi cannot be duplicate and solution cannot be duplicate.
0 solution.
The ides must be using dynamic programming:
dp[i][k], the number of solution of target = i, K = k.
And the iteration relation is :
if(i > num[n-1]) dp[i][k] += dp[i-num[n-1]][k-1];
For three cases, they depend on the runing order of i,n,k. I know the result when there is no restriction of K (sum of any number of variables):
case 1:
int KSum(vector<int>& vec, int target) {
vector<int> dp(target + 1);
dp[0] = 1;
for (int i = 1; i <= target; ++i)
for (int n = 0; n < vec.size(); n++)
if (i >= vec[n]) dp[i] += dp[i - vec[n]];
return dp.back();
}
case 2:
for (int n = 0; n < vec.size(); n++)
for (int i = 1; i <= target; ++i)
case 3:
for (int n = 0; n < vec.size(); n++)
for (int i = target; i >= 1; --i)
When there is additional variable k, do we just simply add the for loop
for(int k = 1; k <= K; k++)
at the outermost layer?
EDIT:
I tried case 1,just add for loop of K most inside:
int KSum(vector<int> vec, int target, int K) {
vector<vector<int>> dp(K+1,vector<int>(target + 1,0));
dp[0][0] = 1;
for (int n = 0; n < vec.size(); n++)
for (int i = 1; i <= target; ++i)
for (int k = 1; k <= K; k++)
{
if (i >= vec[n]) dp[k][i] += dp[k - 1][i - vec[n]];
}
return dp[K][target];
}
Is it true for case 2 and case 3?
In your solution without variable K dp[i] represents how many solutions are there to achieve sum i.
Including the variable K means that we added another dimension to our subproblem. This dimension doesn't necessarily have to be on a specific axis. Your dp array could look like dp[i][k] or dp[k][i].
dp[i][k] means how many solutions to accumulate sum i using k numbers (duplicate or unique)
dp[k][i] means using k numbers how many solutions to accumulate sum i
Both are the same things. Meaning that you can add the loop outside or inside.

Largest sum of all increasing subsequences of length k

I am currently stuck with the classic longest increasing subsequence problem, but there is a slight twist to it. Instead of just finding the longest increasing subsequence, I need to find the largest sum of all increasing subsequences that are of length k.
I have the following pseudo code implemented:
input = [4,13,5,14] k = 2
n = size of input
opt = array of size n which stores the highest increasing subsequence sum up to this index
counts = array of size n which stores the amount of values in the subsequence up to this index
highestSum = -1
FOR i in range(0, n)
high = new data object(value = 0, sum = 0, count = 0)
FOR j in range(i-1, 0, -1)
IF high.sum < opt[j] AND opt[j] < opt[i] AND counts[j] < k
high.value = input[j]
high.sum = opt[j]
high.count = counts[j]
opt[i] = high.sum + input[i]
counts[i] = high.count + 1
IF counts[i] == k
highestSum = higher value between (highestSum, opt[i])
return highestSum
This dynamic programming approach works in most cases, but for the list I outlined above it does not return the optimal subsequence sum. The optimal subsequence sum with length 2 should be 27 (13-14), but 18 is returned (4-14). This is due to the opt and counts array looking like this:
k = 2
input: 0 4 13 5 14
opt: 0 4 17 9 18
counts: 0 1 2 2 2
Due to 13 already having a subsequence of 4-13, and thus its count value (2) is no longer less than k, 14 is unable to accept 13 as a correct subsequence due to its count value.
Are there any suggestions as to what I can change?
You'll need k+1 sorted data structures, one for each possible length of subsequence currently found.
Each structure contains, by the last entry in an optimal subsequence, the current sum. That is, we only care about a subsequence that can lead to the best possible solution. (Technical note. Of those that can lead to the best solution, pick the one whose positions are lexicographically first.) Which will be sorted by increasing last entry, and decreasing sum.
In pseudocode it works like this.
initialize optimal[0..k]
optimal[0][min(sequence) - 1] = 0 # empty set.
for entry in sequence:
for i in k..1:
entry_prev = biggest < entry in optimal[i-1]
if entry_prev is not None:
this_sum = optimal[i-1][entry_prev] + entry
entry_smaller = biggest <= entry in optimal[i-1]
if entry_smaller is None or optimal[i][entry_smaller] < this_sum:
delete (e, v) from optimal[i] where entry <= e and ​v <= this_sum
​ insert (entry, this_sum) into optimal[i]
return optimal[k][largest entry in optimal[k]]
But you need this kind of 2-d structure to keep track of what might happen from here.
The total memory needed is O(k n) and running time will be O(k n log(n)).
It is possible to also reconstruct the optimal subsequence, but that requires a more complex data structure.
Here is a working solution in C++ that runs in O(logn * n * k) time with O(n*k) space. I think you can not make it faster but let me know if you find a faster solution. This is a modification of the solution for from https://stackoverflow.com/questions/16402854/number-of-increasing-subsequences-of-length-k. The key difference here is that we keep track of the maximum sum for each subsequences of different legths instead of accumulating the number of subsequences and we are iterating from the back of the array (since for increasing subsequences that have length larger than k the best k-length subarray will be at the end).
An other trick is that we use the array sums to map index + length combinations to maximum sums.
maxSumIncreasingKLenSeqDP function is the simple dynamic programming solution with O(n * n * k) time complexity.
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <limits.h>
using namespace std;
#include <random>
int maxSumIncreasingKLenSeq(int arr[], size_t n, int k){
// inverse compression: assign N-1, N-2, ... , 1 to smallest, ..., largest
size_t N = 1;
size_t compArr[n];
{
for(size_t i = 0; i<n; ++i)
compArr[i] = arr[i];
// descending order
sort(compArr, compArr + n, greater<int>());
unordered_map<int, size_t> compMap;
for(int val : compArr){
if(compMap.find(val) == compMap.end()){
compMap[val] = N;
++N;
}
}
for(size_t i = 0; i<n; ++i)
compArr[i] = compMap[arr[i]];
}
int sums[n * (k - 1) + n]; // key is combined from index and length by n * (length - 1) + index
for(size_t i = 0; i < n * (k - 1) + n; ++i)
sums[i] = -1;
for(size_t i = 0; i < n; ++i)
sums[i] = arr[i]; // i, 1
int BIT[N];
for(size_t len = 2; len <= k; ++len){
for(size_t i = 0; i<N; ++i)
BIT[i] = INT_MIN;
for(size_t i = 0; i < len - 1; ++i)
sums[n * (len - 1) + i] = INT_MIN;
for(int i = n - len; i >= 0; --i){
int val = sums[n * (len - 2) + i + 1]; // i + 1, len - 1
int idx = compArr[i + 1];
while(idx <= N){
BIT[idx] = max(val, BIT[idx]);
idx += (idx & (-idx));
}
// it does this:
//BIT[compArr[i + 1]] = sums[n * (len - 2) + i + 1];
idx = compArr[i] - 1;
int maxSum = INT_MIN;
while(idx > 0){
maxSum = max(BIT[idx], maxSum);
idx -= (idx & (-idx));
}
sums[n * (len - 1) + i] = maxSum;
// it does this:
//for(int j = 0; j < compArr[i]; ++j)
// sums[n * (len - 1) + i] = max(sums[n * (len - 1) + i], BIT[j]);
if(sums[n * (len - 1) + i] > INT_MIN)
sums[n * (len - 1) + i] += arr[i];
}
}
int maxSum = INT_MIN;
for(int i = n - k; i >= 0; --i)
maxSum = max(maxSum, sums[n * (k - 1) + i]); // i, k
return maxSum;
}
int maxSumIncreasingKLenSeqDP(int arr[], int n, int k){
int sums[n * (k - 1) + n]; // key is combined from index and length by n * (length - 1) + index
for(size_t i = 0; i < n; ++i)
sums[i] = arr[i]; // i, 1
for(int i = 2; i <= k; ++i)
sums[n * (i - 1) + n - 1] = INT_MIN; // n - 1, i
// moving backward since for increasing subsequences it will be the last k items
for(int i = n - 2; i >= 0; --i){
for(size_t len = 2; len <= k; ++len){
int idx = n * (len - 1) + i; // i, length
sums[idx] = INT_MIN;
for(int j = n - 1; j > i; --j){
if(arr[i] < arr[j])
sums[idx] = max(sums[idx], sums[n * (len - 2) + j]); // j, length - 1
}
if(sums[idx] > INT_MIN)
sums[idx] += arr[i];
}
}
int maxSum = INT_MIN;
for(int i = n - k; i >= 0; --i)
maxSum = max(maxSum, sums[n * (k - 1) + i]); // i, k
return maxSum;
}
int main(){
std::random_device dev;
std::mt19937 rng(dev());
std::uniform_int_distribution<std::mt19937::result_type> dist(1,10);
for(int len = 3; len < 10; ++len){
for(int i = 0; i < 10000; ++i){
int arr[100];
for(int n = 0; n < 100; ++n)
arr[n] = dist(rng);
int res = maxSumIncreasingKLenSeqDP(arr, 100, len);
int fastRes = maxSumIncreasingKLenSeq(arr, 100, len);
if(res != fastRes)
cout << "failed" << endl;
else
cout << "passed" << endl;
}
}
return 0;
}

Leetcode Target sum of dynamic programming

Given n and target, find the number of combinations of number from [1,2,...,n] adding up to target. The number can be repeatedly picked (1 + 1 + 2 = 4), however the combinations cannot be duplicated ({1,1,2} and {1,2,1} are regard as one combination). e.g.
n = 2, target = 4: {1,1,1,1}, {1,1,2}, {1,3}, {2,2}, so return 4
Since we only need to return the number of combinations, we use dynamic programming as following:
int sum(int n, int target) {
vector<int> dp(target + 1);
dp[0] = 1;
for (int i = 1; i <= target; ++i) {
for (int j = 1; j <= n; j++) {
if (i >= j) dp[i] += dp[i - j];
}
}
return dp.back();
}
However this solution is for duplicated combinations:{1,1,1,1}, {1,1,2}, {1,2,1}, {2,1,1}, {1,3}, {3,1} {2,2}, so return 7.
Do you know how to modify it to remove the duplications?
Simple modification
for (int j = 1; j <= n; j++) {
for (int i = j; i <= target; i++) {
dp[i] += dp[i - j];
}
}
helps to avoid using small values after larger value, so code counts only sorted combinations
Alike question with specific coin nominals instead of 1..n values

Given a sequence of n positive integers, find a subsequence of length k such that the sum over the absolute values of the differences is maximal

We are given a sequence of n positive integers, which I will denote as a0, a1, …, an-1. We are also given an integer k, and our task is to:
find a subsequence of length exactly k (denoted as b0, b1, …, bk-1), such that abs(b1 - b0) + abs(b2 - b1) + … + abs(bk-1 - bk-2) is maximal; and
output the sum (no need to output the entire subsequence).
I have been trying to solve this using a dynamic programming approach but all my efforts have been futile.
EDIT: k <= n. The elements in the sequence b must appear in the same order as they appear in a (otherwise, this would be solved by simply finding max, min, ... or min, max, ...).
Example input:
n = 10
k = 3
1 9 2 3 6 1 3 2 1 3
Output:
16 (the subsequence is 1 9 1, and abs(9 - 1) + abs(1 - 9) = 8 + 8 = 16)
Any help / hints would be greatly appreciated.
I managed to solve this problem. Here's the full code:
#include <stdio.h>
#include <stdlib.h>
int abs(int a)
{
return (a < 0) ? -a : a;
}
int solve(int *numbers, int N, int K)
{
int **storage = malloc(sizeof(int *) * N);
int i, j, k;
int result = 0;
for (i = 0; i < N; ++i)
*(storage + i) = calloc(K, sizeof(int));
// storage[i][j] keeps the optimal result where j + 1 elements are taken (K = j + 1) with numbers[i] appearing as the last element.
for (i = 1; i < N; ++i) {
for (j = 1; j < K; ++j) {
for (k = j - 1; k < i; ++k) {
if (storage[i][j] < storage[k][j - 1] + abs(numbers[k] - numbers[i]))
storage[i][j] = storage[k][j - 1] + abs(numbers[k] - numbers[i]);
if (j == K - 1 && result < storage[i][j])
result = storage[i][j];
}
}
}
for (i = 0; i < N; ++i)
free(*(storage + i));
free(storage);
return result;
}
int main()
{
int N, K;
scanf("%d %d", &N, &K);
int *numbers = malloc(sizeof(int) * N);
int i;
for (i = 0; i < N; ++i)
scanf("%d", numbers + i);
printf("%d\n", solve(numbers, N, K));
return 0;
}
The idea is simple (thanks to a friend of mine for hinting me at it). As mentioned in the comment, storage[i][j] keeps the optimal result where j + 1 elements are taken (K = j + 1) with numbers[i] appearing as the last element. Then, we simply try out each element appearing as the last one, taking each possible number of 1, 2, ..., K elements out of all. This solution works in O(k * n^2).
I first tried a 0-1 Knapsack approach where I kept the last element I had taken in each [i][j] index. This solution did not give a correct result in just a single test case, but it worked in O(k * n). I think I can see where it would yield a suboptimal solution, but if anyone is interested, I can post that code, too (it is rather messy though).
The code posted here passed on all test cases (if you can detect some possible errors, feel free to state them).

Stuck with an interview Question... Partitioning of an Array

I found the following problem on the internet, and would like to know how I would go about solving it:
Problem: Integer Partition without Rearrangement
Input: An arrangement S of non negative numbers {s1, . . .
, sn} and an integer k.
Output: Partition S into k or fewer ranges, to minimize the maximum
of the sums of all k or fewer ranges,
without reordering any of the
numbers.*
Please help, seems like interesting question... I actually spend quite a lot time in it, but failed to see any solution..
Let's try to solve the problem using dynamic programming.
Note: If k > n we can use only n intervals.
Let consider d[ i ][ j ] is solution of the problem when S = {s1, ..., si } and k = j. So it is easy to see that:
d[ 0 ][ j ] = 0 for each j from 1 to k
d[ i ][ 1 ] = sum(s1...si) for each i from 1 to n
d[ i ][ j ] = minfor t = 1 to i (max ( d[i - t][j - 1], sum(si - t + 1...si)) for i = 1 to n and j = 2 to k
Now let's see why this works:
When there is no elements in the sequence it is clear that only one interval there can be (an empty one) and sum of its elements is 0. That's why d[ 0 ][ j ] = 0 for all j from 1 to k.
When only one interval there can be, it is clear that solution is sum of all elements of the sequence. So d[ i ][ 1 ] = sum(s1...si).
Now let's consider there are i elements in the sequence and number of intervals is j, we can assume that last interval is (si - t + 1...si) where t is positive integer not greater than i, so in that case solution is max ( d[i - t][j - 1], sum(si - t + 1...si), but as we want the solution be minimal we should chose t such to minimize it, so we will get minfor t = 1 to i (max ( d[i - t][j - 1], sum(si - t + 1...si)).
Example:
S = (5,4,1,12), k = 2
d[0][1] = 0, d[0][2] = 0
d[1][1] = 5, d[1][2] = 5
d[2][1] = 9, d[2][2] = 5
d[3][1] = 10, d[3][2] = 5
d[4][1] = 22, d[4][2] = 12
Code:
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main ()
{
int n;
const int INF = 2 * 1000 * 1000 * 1000;
cin >> n;
vector<int> s(n + 1);
for(int i = 1; i <= n; ++i)
cin >> s[i];
vector<int> first_sum(n + 1, 0);
for(int i = 1; i <= n; ++i)
first_sum[i] = first_sum[i - 1] + s[i];
int k;
cin >> k;
vector<vector<int> > d(n + 1);
for(int i = 0; i <= n; ++i)
d[i].resize(k + 1);
//point 1
for(int j = 0; j <= k; ++j)
d[0][j] = 0;
//point 2
for(int i = 1; i <= n; ++i)
d[i][1] = d[i - 1][1] + s[i]; //sum of integers from s[1] to s[i]
//point 3
for(int i = 1; i <= n; ++i)
for(int j = 2; j <= k; ++j)
{
d[i][j] = INF;
for(int t = 1; t <= i; ++t)
d[i][j] = min(d[i][j], max(d[i - t][j - 1], first_sum[i] - first_sum[i - t]));
}
cout << d[n][k] << endl;
return 0;
}
This problem is taken verbatim from Steven Skiena's book "The Algorithm Design Manual". You can read the detailed discussion and his solution on Google Books. Better yet, buy the book.

Resources