Consider an array A with length n. Let k be the length of subsequences to be generated. What I want to do is to get the number of subsequences with length k and sum s.
Example:
A = [1,1,2,2,3]
s = 4
k = 2
So output would be 3 -> [{1,3}, {1,3}, {2,2}].
Note: 1 is considered twice as treated individually.
The total number of subsequences with length k is ⁿCₖ (Here, 10).
What I tried: I tried to generate all subsequences of length k using Pascals Identity, individually calculate their sum and check whether it is equal to sum s or not. How can I make the algorithm more efficient?
Can anyone help me with this?
I don't know much about C++ but this seems to work:
#include <iostream>
using namespace std;
#include <map>
double f(int A[], int n, int s, int k, int i, map<array<int, 3>, double> memo){
if (k == 0)
return s == 0 ? 1 : 0;
if (i == n || s < 0 || k < 0)
return 0;
return memo[array<int, 3>{s, k, i}] =
f(A, n, s - A[i], k - 1, i + 1, memo) + f(A, n, s, k, i + 1, memo);
}
int main(){
map<array<int, 3>, double> memo;
int A[5] = {1, 1, 2, 2, 3};
double result = f(A, 5, 4, 2, 0, memo);
cout << result;
}
This can be solved using the knapsack method. For each element you can either include it or exclude it. Here's the cpp code :
ll knap(int values[],int n, int i, int length, int sum) { //ll is long long
if(s<0 || i>n-1 ||l<0) return 0;
if(s==0 && l==0) return 1;
ll a = knap(values,n,i+1,l-1,s-values[i]); //including current element
ll b = knap(values,n,i+1,l,s); //not including the current element and moving on
return (a+b);
}
Related
When I learned recursion, I understood it with 3 steps, where one of them was the assumption step. For example, if I want to find the sum of n integers:
int func(int n)
{
if(n <= 1)
return n;
int ans = func(n-1); //Assumption step
return ans + n;
}
When n = 5, then In the assumption step I assume that func(n-1) ie; func(4) will give me the correct answer 10. So keeping that assumption in mind, I just write return ans + n; Since I know ans has 10 in it and then just add the current n to it, which will give me my answer of 15.
Now when I look at the knapsack code:
int knapsack(int wt[], int val[], int capacity, int n)
{
if (n == 0 || capacity == 0)
return 0;
if(wt[n-1] > capacity)
return knapsack(wt, val, capacity-wt[n-1], n-1);
return max(val[n-1] + knapsack(wt, val, capacity-wt[n-1], n-1), knapsack(wt, val, capacity, n-1));
}
int main()
{
int wt[] = {1, 3, 4, 5};
int val[] = {1, 4, 5, 7};
int capacity = 7;
cout<<knapsack(wt,val,capacity, 4); // gives 9
}
Which function do I trust to give me the solution for the smaller value n-1 and what will it be. How can I apply and understand the assumption step in the knapsack code?
I have this function that is supposed to count how many duplicates of same number occur in certain array. Important this must be of complexity O(logn).
I wrote this one below, but it doesn't count the duplicates properly.
Also one more thing, the numbers are sorted from lowest to highest.
int CountElementsinFile(int *Arr, int num, int numOfD)
{
int avg{};
int inB = 0;
int inE = numOfD - 1;
int el{};
while (inB <= inE)
{
avg = (inB + inE) / 2;
if (Arr[avg] == num)
el++;
if (Arr[avg] > num)
inE = avg - 1;
else
inB = avg + 1;
}
return el;
}
With std, you might do:
int CountElementsinFile(const int *a, int size, int value)
{
const auto range = std::equal_range(a, a + size, value);
return range.second - range.first;
}
You need to determine the upper and lower boundaries of num subsequence using the Bisection method. You need to rearrange the lower or upper (depending on the comparison) search region boundary in the while loop until inB < inE reducing the region in half. The complexity will be O(ln(n)). You were close, but you will not be able to find both boundaries in one while loop. I just corrected your code.
int CountElementsinFile(int *Arr, int num, int numOfD)
{
// There is no num in the array
if (Arr[0] > num || Arr[numOfD - 1] < num)
return 0;
int avg{};
int lb, ub;
// Find lower boundary
int inB = 0;
int inE = numOfD - 1;
while (inB < inE)
{
// divide search region
avg = (inB + inE) / 2;
if (Arr[avg] >= num)
inE = avg;
else
inB = avg+1;
}
lb = inE;
// Find upper boundary
// inB already found
inE = numOfD - 1;
while (inB < inE)
{
avg = (inB + inE + 1) / 2;
if (Arr[avg] > num)
inE = avg-1;
else
inB = avg;
}
ub = inB;
return ub - lb + 1;
}
int main()
{
int arr[] = { 5, 7, 8, 9, 9, 9, 9, 9, 11 };
std::cout << CountElementsinFile(arr, 9, sizeof(arr) / sizeof(int)) << std::endl;
return 0;
}
From the function signature you gave, I am guessing you were given a number N and a sorted array of numbers and need to count how many times N appears in the array.
Since the array is sorted, you need to find the index (using binary search) of the first number that is smaller than N (this is O(log n)), the index of the first number larger than N (this is also O(log n)), and simply substract one index from the other.
Of course you need to take into account edge cases where there are no numbers smaller than N or larger than N, but that is for you to figure out.
#include<algorithm>
using namespace std;
int CountElementsinFile(int arr[], int size, int numToSearch)
{
return count(arr, arr + size, numToSearch);
}
Briefly about the condition of the problem:
Given the numbers from 1 to n, and m stages of purification, after that follows in m lines with two numbers left and right (borders, inclusive), the range of deleting numbers (1..n), you must output all living elements after removal.
I will give an example:
n = 10, m = 3
Suppose we make an array a[1,2,3,4,5,6,7,8,9,10];
left = 1, right = 2;
After 1 deletion: a[3,4,5,6,7,8,9,10];
left = 4, right = 5;
After 2 deletion: a[3,4,5,8,9,10];
left = 3, right = 5;
After 3 deletion: a[3,4,10];
Conclusion: 3 4 10
So not everything is so simple, the restrictions are strict, namely:
n, m <= 3 * 10 ^ 5
left <= right
My attempt was as follows: I created a vector from numbers from 1 to n and deleted all elements in range [left, right], but Time Limit is coming because of the complexity.
#include <iostream>
#include <vector>
using namespace std;
#define ll uint64_t
int main() {
ll i, n, k, l, r;
cin >> n >> k;
vector <ll> a;
for (i = 1; i <= n; i++) {
a.push_back(i);
}
for (i = 1; i <= k; i++) {
cin >> l >> r;
a.erase(a.begin()+l-1,a.begin()+r);
}
cout << a.size() << endl;
for (auto i : a) {
cout << i << ' ';
}
}
How to solving this problem?
The problem is solvable using a segment tree with lazy propagation and order statistics in O((N + Q) * log(N)) which should pass in a second or two on most online judges given your constraints.
Brief Explanation
'Still Exists' Boolean Array
Let's imagine that we have a boolean array of size N that indicates for each item whether it still exists or removed. The array will be initialized with ones since no elements are removed yet.
Segment Tree
Info Query: Let's build a range-sum segment tree on top of this boolean array (True is mapped to 1 and false is mapped to 0). If we query for any [L, R] range, the segment tree answers with the number of still existing elements. (Note that L and R are indices in the original array -that includes removed and non-removed elements-)
Update Query: The only update query done on the segment tree is to set a range with zeros (marking a range of elements as removed). Since we update a range of elements to zeros, we need to use lazy propagation (No need for it if the problem required removing a single item).
The Final Output
After updating all ranges given to zeros, we can iterate over each index and check if it's zero or one, and print it if it's one, however the solution is not that easy since the ranges provided in the input are not ranges in the original array, it's actually indices in the updated array.
Updated Ranges Problem
To understand the problem more let's go through an example:
Let's assume we're working with an array of length 6, the array is initially: 1 2 3 4 5 6 and the boolean array is initially: 1 1 1 1 1 1
Let's assume that the first deletion is [2, 4], now the new array is: 1 5 6 and the new updated boolean array is: 1 0 0 0 1 1
At this point, if we were asked to print the array, we will simply go through the original array and print the values that only corresponds to true in the boolean array.
Now let's try to delete another range [1, 2], if we simply set the first two elements to zeros, then we will end up with: 0 0 0 0 1 1. Which means that we still have 5, 6 on in our array, while we actually have only 6 after the last deletion.
Order-Statistics to solve the updated ranges problem
To solve the problem, we need to add the order-statistics property to our segment tree. this property will answer the following question: Given X, find the index were the prefix sum of ones that ends with it is X, this will help us map the current [L, R] into new [L, R] that can be used with the original indexing.
To understand the mapping better, let's go back to the second step of our example:
The boolean array was: 1 0 0 0 1 1, Delete elements between L=1 and R=2, using the order-statistics property, L will be mapped to 1 and R will be mapped to 5, now we will update the range between the newL and the newR to zeros and the boolean array becomes 0 0 0 0 0 1.
Code
#include <bits/stdc++.h>
using namespace std;
class SegmentTree {
vector<int> seg, lazy;
int sz;
void build(int ind, int ns, int ne, const vector<int> &v) {
if (ns == ne) {
seg[ind] = v[ns];
return;
}
int mid = ns + (ne - ns) / 2;
build(ind * 2, ns, mid, v);
build(ind * 2 + 1, mid + 1, ne, v);
seg[ind] = seg[ind * 2] + seg[ind * 2 + 1];
}
void probagateLazy(int ind) {
if (lazy[ind]) {
lazy[ind] = 0, seg[ind] = 0;
if (ind * 2 + 1 < 4 * sz)
lazy[ind * 2] = lazy[ind * 2 + 1] = 1;
}
}
int query(int s, int e, int ind, int ns, int ne) {
probagateLazy(ind);
if (e < ns || s > ne)
return 0;
if (s <= ns && ne <= e)
return seg[ind];
int mid = ns + (ne - ns) / 2;
return query(s, e, ind * 2, ns, mid) + query(s, e, ind * 2 + 1, mid + 1, ne);
}
void update(int s, int e, int ind, int ns, int ne) {
probagateLazy(ind);
if (e < ns || s > ne)
return;
if (s <= ns && ne <= e) {
lazy[ind] = 1;
probagateLazy(ind);
return;
}
int mid = ns + (ne - ns) / 2;
update(s, e, ind * 2, ns, mid);
update(s, e, ind * 2 + 1, mid + 1, ne);
seg[ind] = seg[ind * 2] + seg[ind * 2 + 1];
}
int find(int pos, int ind, int ns, int ne) {
probagateLazy(ind);
if (ns == ne)
return ns;
probagateLazy(ind * 2);
probagateLazy(ind * 2 + 1);
int mid = ns + (ne - ns) / 2;
if (pos <= seg[ind * 2])
return find(pos, ind * 2, ns, mid);
return find(pos - seg[ind * 2], ind * 2 + 1, mid + 1, ne);
}
public:
SegmentTree(int sz, const vector<int> &v) {
this->sz = sz;
seg = vector<int>(sz * 4);
lazy = vector<int>(sz * 4);
build(1, 0, sz - 1, v);
}
int query(int s, int e) {
return query(s, e, 1, 0, sz - 1);
}
int update(int s, int e) {
update(s, e, 1, 0, sz - 1);
}
int find(int pos) {
return find(pos, 1, 0, sz - 1);
}
};
int main() {
int i, n, k, l, r;
scanf("%d %d", &n, &k);
vector<int> a;
for (i = 1; i <= n; i++) {
a.push_back(i);
}
vector<int> v(n, 1);
SegmentTree st(n, v);
while (k--) {
scanf("%d %d", &l, &r);
int newL = st.find(l);
int newR = st.find(r);
st.update(newL, newR);
}
vector<int> ans;
for (int i = 0; i < n; i++) {
if (st.query(i, i))
ans.push_back(a[i]);
}
printf("%d\n", ans.size());
for (int i = 0; i < ans.size(); i++) {
printf("%d ", ans[i]);
}
}
Black Boxing the Segment Tree
If you're not familiar with segment trees, then it's expected to find the code hard to understand, so I'll try to make it easier by ignoring the internal implementation of the segment tree and give you a quick look at its functionalities.
Query Method
The query method takes as an input the start and end index of the range to be queried and returns the summation of the elements inside this range.
Update Method
The update method takes as input the start and end index of the range to be updated, and set all items inside this range to zeros
Find Method
The find method takes as an input X and returns the first element Y were the sum of elements in the range [0, Y] is X
Other Solutions
The problem can also be solved using Splay Tree or Treap data structure.
I have a c++ program which calculates maximum of a array provided no two consecutive elements of array can be taken.
For eg:
7 3 4 6 will result in a answer of 13 .Here we chose 7 and 6 for optimal maximum.
Here is my recursive program for it.
#include <iostream>
using namespace std;
int n;
int findMax(int x,int ar[])
{
if(x < n)
return max( ar[x]+findMax(x+2,ar), findMax(x+1,ar));
return 0;
}
int main(){
int ar[]={1,7,4,4,9,5,12};
n = sizeof(ar)/sizeof(ar[0]);
cout<<findMax(0,ar);
return 0;
}
However I am more interested in the indices of array which were chosen for this purpose by my program .How can I do that efficiently.
In the above program answer should be 1,4,6 as we chose 1st , 4th and 6th element of the array for the maximum.
Note: I am using 0 based indexing.
Thanks.
A recurrence relation R(k) for the maximum sum of the first k elements of the array (with no adjacent terms) is:
R(0) = 0, R(1) = max(0, a[0])
R(k) = max(a[k] + R(k-2), R(k-1))
This is almost the same recurrence you're using in your code, but in your code your function returns the maximum sum of elements k and later.
Anyway, you can build a table of these values in linear time using dynamic programming. In pseudocode:
R = new array of length n+1
R[0] = 0
R[1] = max(0, a[0])
for i = 2 .. n
R[i] = max(a[i-1] + R[i-2], R[i-1])
If you just want the maximum sum, you can return R[n]. But you can also reconstruct the indices easily. In pseudo-code:
indices(a, R):
result = new empty vector
i = n
while i > 0
if (i == 1 and a[0] > 0) or R[i] == a[i-1] + R[i-2]
result.push_back(i-1)
i -= 2
else
i -= 1
You'll have to reverse result to get the indices in increasing order.
This is definitely not the most effective solution but probably the one with least implementation effort:
#include <iostream>
#include <vector>
using namespace std;
int n;
pair<int, vector<int> > findMax(int x, int ar[])
{
if (x < n) {
pair<int, vector<int> > max1 = findMax(x + 2, ar);
const pair<int, vector<int> > max2 = findMax(x + 1, ar);
max1.first += ar[x];
max1.second.insert(max1.second.begin(), x);
return max1.first >= max2.first ? max1 : max2;
}
return make_pair(0, vector<int>());
}
ostream& operator<<(ostream &out, const vector<int> &vec)
{
const char *sep = "";
for (int value : vec) {
out << sep << value; sep = ", ";
}
return out;
}
int main()
{
int ar[]={1,7,4,4,9,5,12};
n = sizeof ar / sizeof *ar;
const pair<int, vector<int> > maxAr = findMax(0, ar);
cout << maxAr.first << '\n'
<< maxAr.second << '\n';
return 0;
}
Output:
28
1, 4, 6
Life demo on coliru
Thereby, the return value is extended with a std::vector<int> which holds the used indices beside of the current sum.
std::max() could be used if I would provide a suitable (overloadeded) operator<() for std::pair<int, std::vector<int> >. To not make things over-complicated, I just replaced std::max() by the resp. condition.
I think below code will satisfy your need.
#include<bits/stdc++.h>
using namespace std;
int n;
void findMax(int arr[], int in, pair< int, vector<int> > tempStore,
pair< int, vector<int> > &resStore) {
if(in >=n) {
if(resStore.first < tempStore.first) {
resStore.first = tempStore.first;
resStore.second = tempStore.second;
}
return;
}
findMax(arr, in+1, tempStore, resStore);
tempStore.first += arr[in];
tempStore.second.push_back(in);
findMax(arr, in+2, tempStore, resStore);
}
int main() {
int ar[]={1,7,4,4,9,5,12};
n = sizeof(ar)/sizeof(ar[0]);
pair< int, vector<int> > resStore, tempStore;
findMax(ar, 0,tempStore,resStore);
cout<<"Result Value: "<<resStore.first;
cout<<"\nResult Index:\n";
for(int i=0; i<resStore.second.size(); i++) {
cout<<resStore.second[i]<<" ";
}
return 0;
}
I have a question regarding already asked this question:
SPOJ DQUERY : TLE Even With BIT?
What if I would like to not consider the repeated element to count when I make a range query?
following is an example:
Input
Line 1: n (1 ≤ n ≤ 10^6).
Line 2: n numbers a1, a2, ..., an (-10^9 ≤ ai ≤ ).
Line 3: q (1 ≤ q ≤ 10^6), the number of d-queries.
In the next q lines, each line contains 2 numbers i, j
representing a d-query (1 ≤ i ≤ j ≤ n).
Output
For each d-query (i, j), print the number of distinct elements in the
subsequence ai, ai+1, ..., aj in a single line.
Example
Input
9
1 2 3 2 4 1 2 3 4
3
1 9
2 4
5 9
2 7
Output
0 //Explanation: all elements have been repeated.
1 //Explanation: only 3 has not repeated.
3 //Explanation: only 4 is repeated, so count only 1, 2 and 3.
3 //Explanation: only 2 is repeated, so count only 3, 4 and 1.
what could it be the necessary changes which should have done in #kraskevich 's answer(which is an efficient solution for that particular case)? I tried to add 0 in BIT, instead of -1 in above-mentioned solution, which does not help for all types of queries. Can anybody get me an idea?
I finally made it using MOs Algorithm. Following will work as expected.
/** For the given set of queries find the Unique element
* count of an array using MO's Algorithum. */
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <unordered_map>
using namespace std;
struct Query // struct for storing the queries
{
int Left;
int Right;
int Index;
};
inline void Add(const int i, int &ans, vector<int> &Arr, vector<int> &countArray)
{
++countArray[Arr[i]];
if(countArray[Arr[i]] == 1)
ans += countArray[Arr[i]];
if(countArray[Arr[i]] == 2)
ans -= countArray[Arr[i]];
}
inline void Remove(const int i, int &ans, vector<int> &Arr, vector<int> &countArray)
{
--countArray[Arr[i]];
if(countArray[Arr[i]] == 1)
ans += countArray[Arr[i]];
if(countArray[Arr[i]] == 0)
ans -= countArray[Arr[i]];
}
int main()
{
int _size; cin >> _size;
vector<int> Arr; Arr.reserve(_size);
copy_n(istream_iterator<int>(cin), _size, back_inserter(Arr));
//copy(Arr.cbegin(), Arr.cend(), ostream_iterator<int>(cout, "\t"));
int id = -1;
int sqrt_n = sqrt(_size);
int Q; cin >> Q;
vector<Query> qArr(Q);
unordered_map<int, int> Map;
for (int i = 0; i < _size; ++i)
{
if (Map.count(Arr[i]) == 0)
Map[Arr[i]] = ++id;
Arr[i] = Map[Arr[i]];
}
// read queries
for (int i = 0; i < Q; ++i)
{
int L,R;
cin >> L >> R;
qArr[i].Left = L-1;
qArr[i].Right = R-1;
qArr[i].Index = i;
}
// sort the queries according to(MO's Algorithum)
sort(qArr.begin(),qArr.end(),
[&](const Query &lhs, const Query &rhs)->bool
{
return ( (lhs.Left/sqrt_n == rhs.Left/sqrt_n) ?
lhs.Right < rhs.Right: // Qs with same Left case
(lhs.Left / sqrt_n) < (rhs.Left / sqrt_n) ); // Qs with diff values case
});
int currStart = 0;
int currEnd = 0;
int tempAnswer= 0;
vector<int> Answer(Q);
vector<int> countArray(_size);
for (int i = 0; i < Q; ++i)
{
int L = qArr[i].Left;
int R = qArr[i].Right;
/** Remove extra elements of previous range. For
* example if previous range is [0, 3] and current
* range is [2, 5], then a[0] and a[1] are subtracted */
while (currStart < L)
{
Remove(currStart, tempAnswer, Arr, countArray);
++currStart;
}
/** Add Elements of current Range */
while (currStart > L)
{
Add(currStart - 1, tempAnswer, Arr, countArray);
--currStart;
}
while (currEnd <= R)
{
Add(currEnd, tempAnswer, Arr, countArray);
++currEnd;
}
/** Remove elements of previous range. For example
* when previous range is [0, 10] and current range
* is [3, 8], then a[9] and a[10] are subtracted */
while (currEnd > R + 1)
{
Remove(currEnd - 1, tempAnswer, Arr, countArray);
--currEnd;
}
Answer[qArr[i].Index] = tempAnswer;
}
for(const auto &it: Answer) cout<<it<<endl;
return 0;
}