Fenwick Tree HackerEarth - fenwick-tree

I have the following implementation of a Fenwick tree to solve the following Question on HackeEarth.
#include <iostream>
#define MAX 1000000007
using namespace std;
long long int dp[500006];
long long int GCD[500006];
// Function to Calculate GCD
int gcd(int u, int v){
int shl = 0;
while ( u && v && u!=v ) {
bool eu = !(u & 1);
bool ev = !(v & 1);
if ( eu && ev ) {
++shl;
u >>= 1;
v >>= 1;
}
else if ( eu && !ev ) u >>= 1;
else if ( !eu && ev ) v >>= 1;
else if ( u>=v ) u = (u-v)>>1;
else {
int tmp = u;
u = (v-u)>>1;
v = tmp;
}
}
return !u? v<<shl : u<<shl;
}
//Function to calculate Cumulative GCD
long long int cumulativeGCD(int x){
long long int sum = 0;
if(!dp[x]){
for(int i=1;i<=x;i++){
sum += gcd(i,x);
}
dp[x] = sum;
return sum;
}
else return dp[x];
}
// Retrieve the SUM function
long long int getSum(long long int BITree[], int index)
{
long long int sum = 0; // Iniialize result
// index in BITree[] is 1 more than the index in arr[]
index = index + 1;
// Traverse ancestors of BITree[index]
while (index>0)
{
// Add current element of BITree to sum
sum += BITree[index];
// Move index to parent node in getSum View
index -= index & (-index);
}
return sum;
}
// Update BIT function
void updateBIT(long long int BITree[], int n, int index, long long int val)
{
// index in BITree[] is 1 more than the index in arr[]
index = index + 1;
// Traverse all ancestors and add 'val'
while (index <= n)
{
// Add 'val' to current node of BI Tree
if(BITree[index]>MAX)
BITree[index] = (BITree[index] + val)%MAX;
else BITree[index] += val;
// Update index to that of parent in update View
index += index & (-index);
}
}
// Construct BIT function
long long int *constructBIT(int arr[], int size){
long long int *BITree = new long long int[size+1]();
for (int i=0; i<size; i++)
updateBIT(BITree, size, i, GCD[i]);
return BITree;
}
int main()
{
int size,queries,index,value,start,end;
char type;
scanf("%d",&size);
int *arr= new int[size];
for(int i=0;i<size;i++){
scanf("%d",&arr[i]);
GCD[i] = cumulativeGCD(arr[i]);
}
long long int *BIT = constructBIT(arr,size);
scanf("%d",&queries);
while(queries--){
cin>>type;
if(type=='C'){
scanf("%d %d",&start,&end);
printf("%lld\n",getSum(BIT,end-1) - getSum(BIT,start-2));
}
if(type=='U'){
scanf("%d %d",&index,&value);
long long int diff = cumulativeGCD(value)-cumulativeGCD(arr[index-1]);
updateBIT(BIT,size,index-1,diff);
}
}
return 0;
}
My solution is exceeding the time limit for 7 out of the 10 tests cases. I am not able to optimize this code further. How could I possibly optimize this so that it may run under 1 sec for each of the test cases. Thank you very much !

Provide the link that points to the problem that you're solving, so that we can better understand the scenario and suggest you. However, the gcd() function can be modified as:
typedef long long ll;
ll gcd(ll a,ll b){
if(!b)
return a;
else return gcd(b,a%b);
}
remove
if(BITree[index]>MAX)
BITree[index] = (BITree[index] + val)%MAX;
else BITree[index] += val;
and replace with
BITree[index] = (BITree[index] + val) % MAX;
as you're not checking BITree[index] + val > MAX

Related

selection sort using recursion

void swap(int a[], int x, int y)
{
int temp = a[x];
a[x] = a[y];
a[y] = temp;
}
void sort(int arr[], int x)
{
static int count = 0;
if (x == 1)
{
return;
}
int min = 100; // random value
int index;
for (int i = 0; i < x; i++)
{
if (arr[i] < min)
{
min = arr[i];
index = i;
}
}
swap(arr, count, index);
count++;
sort(arr + 1, x - 1);
}
int main()
{
int x;
cin >> x;
int A[x];
for (int i = 0; i < x; i++)
{
cin >> A[i];
}
sort(A, x);
for (int i = 0; i < x; i++)
{
cout << A[i] << " ";
}
cout << endl;
return 0;
}
this code is of selection sort using recursion. It is printing garbage values. what's the mistake in this. i am not sure but i guess because of using the static variable in the sort function(). it is printing garbage values
Replace swap(arr, count, index); with
swap(arr, 0, index);
and remove static int count = 0;.
Replace sort(A, x); in the main with
sort(A, x - 1);
and change the condition if (x == 1) to if (x == 0).
I suggest to rename index to last.
Replace min = 100; with
min = arr[0];
For starters variable length arrays like this
int x;
cin >> x;
int A[x];
is not a standard C++ feature.
Nevertheless the function can invoke undefined behavior when for example is called with the second parameter equal to 0.
Also there is no sense to declare the static variable.
The function will not sort an array elements of which have values greater than 100.
The variable index must be initialized to 0 before the for loop.
Also there is already the standard function std::swap that swaps two objects.
The function can be defined the following way
#include <algorithm>
void selection_sort( int a[], size_t n )
{
if ( not ( n < 2 ) )
{
auto it = std::min_element( a, a + n );
if ( it != a ) std::iter_swap( a, it );
selection_sort( a + 1, n - 1 );
}
}
If you do not know yet standard algorithms then the functions can look the following way
void swap( int &a, int &b )
{
int rmp = a;
a = b;
b = tmp;
}
void selection_sort( int a[], size_t n )
{
if ( not ( n < 2 ) )
{
size_t index = 0;
for ( size_t i = 1; i < n; i++ )
{
if ( a[i] < a[index] ) index = i;
}
if ( index != 0 ) swap( a[0], a[index] );
selection_sort( a + 1, n - 1 );
}
}
One of the easy ways of doing the selection sort using recursion is as follows:
#include<iostream>
using namespace std;
void selectionSort(int *arr, int size,int minIndex){
//base case
if(size ==0 || size ==1 || minIndex == size){
return;
}
//processing
for(int i=minIndex+1;i<size;i++){
if(arr[i]<arr[minIndex]){
swap(arr[minIndex], arr[i]);
}
}
//recursive call
selectionSort(arr,size,minIndex+1);
}
int main(){
int arr[7]={7,6,5,4,3,2,1};
int size = 7;
int minIndex = 0;
selectionSort(arr,size,minIndex);
for(int i=0;i<7;i++){
cout<<arr[i]<<" ";
}
}
We are creating a minIndex at the starting of the array and comparing it with the values in the remaining array, to get the minimum value of the whole array on the left-most side. At each recursive call, we will increment the place of minIndex for further comparison. Hope this helps.
a=[6,5,4,3,2,1,0,-1]
length=a.length
cur=0
n=cur+1
function fun(n)
{
if(cur==length-1)
{
return a
}
else if(a[cur]>a[n])
{
temp=a[cur]
a[cur]=a[n]
a[n]=temp
if(n==length-1)
{
n=cur
cur++
}
// console.log(a)
// console.log(cur)
return fun(n+1)
}
else
{
if(n==length-1)
{
n=cur
cur++
}
return fun(n+1)
}
}
let t=[]
t=[...fun(n)]
console.log(t)

optimising count of inversion(i.e for i<j, a[i]>a[j]) for a large array

I am trying to count inversion(for eg.,for array [2,5,4,1] the inversion count is=4 namely (2,1),(5,4),(5,1),(4,1) using divide and conquer for a large set of arrays, I am getting a recursive count of value when a function executes each merge sort. I store all the count values in a vector and then again use sum operations, it works well for an array size of 70,000 but fails after it. I feel I am unnecessarily storing a large value to vector, instead, I am looking for a way to directly count the same but I am not getting a way to do the same, please help me in achieving it.
ps:the file link is this.
my code looks like;
#include<iostream>
#include<vector>
#include<fstream>
using namespace std;
long long greater_v(long long *array,long long ap,long long p){
long long numx=0;
for(long long i=0;i<p;i++){
if(array[i]>ap){
numx++;
}
}
return numx;
}
long long merge(long long U[],long long Lu,long long V[],long long Lv,long long S[],long long count1){
long long uf=0;long long vf=0;
for(long long sb=0;sb<Lu+Lv;sb++){
if(uf<Lu && vf<Lv){
if(U[uf]<V[vf]){
S[sb]=U[uf];uf++;}
else{
S[sb]=V[vf];
count1=count1+=greater_v(U,V[vf],Lu);
vf++;
}
}
else if(uf<Lu){
S[sb]=U[uf];uf++;
}
else{
S[sb]=V[vf];vf++;
}
}
return count1;
}
In this part I am looking for help where I am storing the value in the vector, instead, i want a way to directly count.
vector<unsigned long long int>v_val;
void MergeSort(long long arr[],long long n){
long long count=0;
//cout<<"sorting ";print(arr,n);
if(n==1)
return;
long long U[n/2];long long V[n-n/2];
for(long long i=0;i<n/2;i++){
U[i]=arr[i];
}
for(long long i=0;i<n-n/2;i++){
V[i]=arr[i+n/2];
}
MergeSort(U,n/2);
MergeSort(V,n-n/2);
count+=merge(U,n/2,V,n-n/2,arr,count);
v_val.push_back(count);
}
main function is;
int main(){
long long test_count=0;
ifstream file_num("pr_as_2.txt");
long long arr_num[100000];
for(long long i=0;i<100000;i++){
file_num>>arr_num[i];
}
unsigned long long int sum_val=0;
MergeSort(arr_num,70000);
for(size_t i=0;i<v_val.size();i++){
sum_val+=v_val[i];
}
cout<<sum_val;
}
look at this approach, it worked for me.
#include <bits/stdc++.h>
using namespace std;
// First subarray is arr[l..m]
// Second subarray is arr[m+1..r]
unsigned int merge(int arr[], int temp[], int l, int m, int r) {
unsigned int inversions = 0;
int i = l;
int j = m;
int k = l;
while (i < m && j <= r) {
if (arr[i] <= arr[j]) {
temp[k] = arr[i];
i++;
} else {
temp[k] = arr[j];
j++;
inversions += m-i;
}
k++;
}
while (i < m) {
temp[k] = arr[i];
i++;
k++;
}
while (j <= r) {
temp[k] = arr[j];
j++;
k++;
}
for (int i = l; i <= r; i++) {
arr[i] = temp[i];
}
return inversions;
}
unsigned int count(int arr[], int temp[], int l, int r) {
unsigned int inversions = 0;
if (r > l) {
int m = (r+l)/2;
inversions = count(arr, temp, l, m);
inversions += count(arr, temp, m+1, r);
inversions += merge(arr, temp, l, m+1, r);
}
return inversions;
}
int main() {
int arr_size = 100000;
int arr[arr_size];
ifstream file("IntegerArray.txt");
string str;
int i = 0;
while (getline(file, str)) {
arr[i] = stoi(str);
i++;
}
// int arr[] = { 1, 20, 6, 4, 5 };
// int arr_size = sizeof(arr) / sizeof(arr[0]);
int temp[arr_size];
/* mergeSort(arr, 0, arr_size-1);
for (int i = 0; i < arr_size; i++) {
cout << arr[i] << " ";
} */
cout << count(arr, temp, 0, arr_size-1) << endl;
}

Sum and sum of squares of digits -coprime

For the paragraph L, R
its sum of digits and the sum of its squares (in the decimal) is co-
prime.
Count how many numbers in the paragraph L, R meet the above conditions
I was stuck on the sub21
exceeds time limit when R = 10^8 and Max R = 10^18:
#include<bits/stdc++.h>
using namespace std;
class tinhtong
{
public:
long long getSum(long long n)
{
long long int sum = 0;
while (n != 0)
{
sum = sum + (n % 10);
n = n/10;
}
return sum;
}
};
class binhphuong
{
public:
long long getpow(long long n)
{
long long poww = 0;
while (n != 0)
{
poww = poww + (n % 10)*(n % 10);
n = n/10;
}
return poww;
}
};
int main()
{
tinhtong g;
binhphuong h;
long long TONG=0,k,l,ucln;
long long int m,n;
cin>>n>>m;
for(n;n<=m;n++)
{
ucln=0;
k=g.getSum(n);
l=h.getpow(n);
while(k!=0 && l!=0)
{
if(k>l)
k-=l;
else
l-=k;
}
if(k==0)
ucln=l;
else
ucln=k;
if (ucln==1)
TONG++;
}
cout<<TONG;
return 0;
}
As mentioned in comments, you can calculate the sum and the sum of squares in one loop, avoiding multiple calls of same % operation.
Moreover, to calculate that two numbers are coprime, it is better to use the version of Euclide's algorithm that uses modulo instead of substractions. The code is below.
In this code, I use the fact that the sum of squares is greater or equal the sum.
I also use the fact that if the sum is a multiple of 2, it is also the case for the sum of squares.
If this code is not fast enough, you can try the suggestion in a comment to first convert the number to a string.
Another possibility would be the check if both numbers are multiple of 3 or 5, before calculating the GCD, as GCD calculation can be longer.
#include <iostream>
#include <tuple>
std::pair<long long, long long> getSum_pow(long long n) {
long long int sum = 0;
long long int sumP = 0;
while (n != 0) {
long long r = n%10;
sum += r;
sumP += r*r;
n = n/10;
}
return {sumP, sum};
};
int main() {
long long TONG = 0, a, b;
long long int m, n;
std::cin >> n >> m;
for(; n <= m; n++) {
std::tie (a, b) = getSum_pow(n);
if (b%2 == 0) continue;
while (b != 0) {
a = a%b;
std::swap (a, b);
}
if (a == 1) {
TONG++;
}
}
std::cout << TONG;
return 0;
}

Solving 5SUM in O(n^3) with strict memory limits

I need a way to solve the classic 5SUM problem without hashing or with a memory efficient way of hashing.
The problem asks you to find how many subsequences in a given array of length N have the sum equal to S
Ex:
Input
6 5
1 1 1 1 1 1
Output
6
The restrictions are:
N <= 1000 ( size of the array )
S <= 400000000 ( the sum of the subsequence )
Memory usage <= 5555 kbs
Execution time 2.2s
I'm pretty sure the excepted complexity is O(N^3). Due to the memory limitations hashing doesn't provide an actual O(1) time.
The best I got was 70 points using this code. ( I got TLE on 6 tests )
#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
#define MAX 1003
#define MOD 10472
using namespace std;
ifstream in("take5.in");
ofstream out("take5.out");
vector<pair<int, int>> has[MOD];
int v[MAX];
int pnt;
vector<pair<int, int>>::iterator it;
inline void ins(int val) {
pnt = val%MOD;
it = lower_bound(has[pnt].begin(), has[pnt].end(), make_pair(val, -1));
if(it == has[pnt].end() || it->first != val) {
has[pnt].push_back({val, 1});
sort(has[pnt].begin(), has[pnt].end());
return;
}
it->second++;
}
inline int get(int val) {
pnt = val%MOD;
it = lower_bound(has[pnt].begin(), has[pnt].end(), make_pair(val, -1));
if(it == has[pnt].end() || it->first != val)
return 0;
return it->second;
}
int main() {
int n,S;
int ach = 0;
int am = 0;
int rez = 0;
in >> n >> S;
for(int i = 1; i <= n; i++)
in >> v[i];
sort(v+1, v+n+1);
for(int i = n; i >= 1; i--) {
if(v[i] > S)
continue;
for(int j = i+1; j <= n; j++) {
if(v[i]+v[j] > S)
break;
ins(v[i]+v[j]);
}
int I = i-1;
if(S-v[I] < 0)
continue;
for(int j = 1; j <= I-1; j++) {
if(S-v[I]-v[j] < 0)
break;
for(int k = 1; k <= j-1; k++) {
if(S-v[I]-v[j]-v[k] < 0)
break;
ach = S-v[I]-v[j]-v[k];
rez += get(ach);
}
}
}
out << rez << '\n';
return 0;
}
I think it can be done. We are looking for all subsets of 5 items in the array arr with the correct SUM. We have array with indexes 0..N-1. Third item of those five can have index i in range 2..N-3. We cycle through all those indexes. For every index i we generate all combinations of two numbers for index in range 0..i-1 on the left of index i and all combinations of two numbers for index in the range i+1..N-1 on the right of index i. For every index i there are less than N*N combinations on the left plus on the right side. We would store only sum for every combination, so it would not be more than 1000 * 1000 * 4 = 4MB.
Now we have two sequences of numbers (the sums) and task is this: Take one number from first sequence and one number from second sequence and get sum equal to Si = SUM - arr[i]. How many combinations are there? To do it efficiently, sequences have to be sorted. Say first is sorted ascending and have numbers a, a, a, b, c ,.... Second is sorted descending and have numbers Z, Z, Y, X, W, .... If a + Z > Si then we can throw Z away, because we do not have smaller number to match. If a + Z < Si we can throw away a, because we do not have bigger number to match. And if a + Z = Si we have 2 * 3 = 6 new combinations and get rid of both a and Z. If we get sorting for free, it is nice O(N^3) algorithm.
While sorting is not for free, it is O(N * N^2 * log(N^2)) = O(N^3 * log(N)). We need to do sorting in linear time, which is not possible. Or is it? In index i+1 we can reuse sequences from index i. There are only few new combinations for i+1 - only those that involve number arr[i] together with some number from index 0..i-1. If we sort them (and we can, because there are not N*N of them, but N at most), all we need is to merge two sorted sequences. And that can be done in linear time. We can even avoid sorting completely if we sort arr at the beginning. We just merge.
For second sequence the merging does not involve adding but removing, but it is very simmilar.
The implementation seems to work, but I expect there is off by one error somewhere ;-)
#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
using namespace std;
int Generate(int arr[], int i, int sums[], int N, int NN)
{
int p1 = 0;
for (int i1 = 0; i1 < i - 1; ++i1)
{
int ai = arr[i1];
for (int i2 = i1 + 1; i2 < i; ++i2)
{
sums[p1++] = ai + arr[i2];
}
}
sort(sums, sums + p1);
return p1;
}
int Combinations(int n, int sums[], int p1, int p2, int NN)
{
int cnt = 0;
int a = 0;
int b = NN - p2;
do
{
int state = sums[a] + sums[b] - n;
if (state > 0) { ++b; }
else if (state < 0) { ++a; }
else
{
int cnta = 0;
int lastA = sums[a];
while (a < p1 && sums[a] == lastA) { a++; cnta++; }
int cntb = 0;
int lastB = sums[b];
while (b < NN && sums[b] == lastB) { b++; cntb++; }
cnt += cnta * cntb;
}
} while (b < NN && a < p1);
return cnt;
}
int Add(int arr[], int i, int sums[], int p2, int N, int NN)
{
int ii = N - 1;
int n = arr[i];
int nn = n + arr[ii--];
int ip = NN - p2;
int newP2 = p2 + N - i - 1;
for (int p = NN - newP2; p < NN; ++p)
{
if (ip < NN && (ii < i || sums[ip] > nn))
{
sums[p] = sums[ip++];
}
else
{
sums[p] = nn;
nn = n + arr[ii--];
}
}
return newP2;
}
int Remove(int arr[], int i, int sums[], int p1)
{
int ii = 0;
int n = arr[i];
int nn = n + arr[ii++];
int pp = 0;
int p = 0;
for (; p < p1 - i; ++p)
{
while (ii <= i && sums[pp] == nn)
{
++pp;
nn = n + arr[ii++];
}
sums[p] = sums[pp++];
}
return p;
}
int main() {
ifstream in("take5.in");
ofstream out("take5.out");
int N, SUM;
in >> N >> SUM;
int* arr = new int[N];
for (int i = 0; i < N; i++)
in >> arr[i];
sort(arr, arr + N);
int NN = (N - 3) * (N - 4) / 2 + 1;
int* sums = new int[NN];
int combinations = 0;
int p1 = 0;
int p2 = 1;
for (int i = N - 3; i >= 2; --i)
{
if (p1 == 0)
{
p1 = Generate(arr, i, sums, N, NN);
sums[NN - 1] = arr[N - 1] + arr[N - 2];
}
else
{
p1 = Remove(arr, i, sums, p1);
p2 = Add(arr, i + 1, sums, p2, N, NN);
}
combinations += Combinations(SUM - arr[i], sums, p1, p2, NN);
}
out << combinations << '\n';
return 0;
}

computes the number of ways to partition n into the sum of positive integers c++

I need to write function as part of assignment..
I need to compute the number of ways to partition n into the sum of positive integers and I can't use for while or goto
/*
* REQUIRES: n > 0
* EFFECTS: computes the number of ways to partition n into the sum of
* positive integers
* MUST be tree recursive
* Hint: Use a helper function that computes the number of ways to
* partition n using a bounded subset of integers. Then use logic
* similar to count_change() from lecture to divide partitions into
* those that use a specific item and those that do not.
*/
int num_partitions(int n);
I figured a way to print them but unable to count it and my function also needed for loop. Here's function
void print(int n, int * a) {
int i ;
for (i = 0; i <= n; i++) {
printf("%d", a[i]);
}
printf("\n");
}
int integerPartition(int n, int * a, int level,int c){
int first;
int i;
if (n < 1)
{
return c;
}
a[level] = n;
print(level, a);
c++;
first = (level == 0) ? 1 : a[level-1];
for(i = first; i <= n / 2; i++){
a[level] = i;
integerPartition(n - i, a, level + 1,c);
}
}
int num_partitions(int n){
int * a = (int * ) malloc(sizeof(int) * n);
return integerPartition (n, a, 0,0);
}
please help...
here is the count change function
int count_change(int amount, const int coins[], int num_coins) {
if (amount == 0) {
return 1;
} else if​ (amount < 0 || num_coins < 1) {
return 0;
} else {
return
count_change(amount - coins[num_coins - 1], coins, num_coins) +
count_change(amount, coins, num_coins - 1);
}
}
You can do it like this:
#include <conio.h>
#include <iostream>
using namespace std;
int integerPartition(int n, int k);
int main()
{
int n;
cin>>n;
int k =n;
cout<<integerPartition(n,k);
getchar();
return 0;
}
int integerPartition(int n, int k)
{
if(k==0)
return 0;
if(n ==0)
return 1;
if(n<0)
return 0;
return integerPartition(n,k-1) + integerPartition(n-k,k);
}
Inspired from: http://www.programminglogic.com/integer-partition-algorithm/
or you can also use: recurrence formula for partition functions, given on
https://en.wikipedia.org/wiki/Partition_(number_theory)