I've attempted to solve a coding contest out of curiosity. Out there, there's one of the problems which couldn't pass all the test cases for my solution. Could there be any improvement in my solution that you would suggest that might help? TIA. The problem along with my solution is stated down below.
The Constraints:
1 ≤ M,N ≤ 10^7,
1 ≤ a[i],b[i] ≤ 10^7
The Output:
Print a single int that the maximum cool value that he
can obtain after buying two items with the given
amount of money
And my solution is:
#include<bits/stdc++.h>
using namespace std;
int main()
{
long long N, M, C, count;
cin>>N>>M>>C;
long long a[N], b[M];
for(long long i=0; i<N; i++){
cin>>a[i];
}
for(long long i=0; i<M; i++){
cin>>b[i];
}
sort(a, a+N);
sort(b, b+M);
if(a[N-1] + b[M-1] <= C){
count = (N-1) + (M-1);
cout<<count<<endl;
}
else{
cout<<"Not even closer"<<endl;
}
return 0;
}
Can anyone suggest what I could improve here to pass all the test?
After sorting, the price a[i] has a coolness equal to i.
Therefore, a solution consists in sorting a and b, and then maximize i+j such that a[i]+a[j] <= C
This last optimisation is performed by a simple for loop, with two indices, one for a and one for b
Complexity is dominated by sorting: O(NlogN + MlogM)
Note: the code currently posted in the question was edited after some comments, and do not correspond to the original code
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::ios_base::sync_with_stdio(false);
std::cin.tie(NULL);
int N, M, C;
std::cin >> N >> M >> C;
std::vector<int> a(N), b(M);
for (int i = 0; i < N; i++){
std::cin >> a[i];
}
for (int i = 0; i < M; i++){
std::cin >> b[i];
}
sort(a.begin(), a.end());
sort(b.begin(), b.end());
if(a[0] + b[0] > C) {
std::cout <<"E kemon aynabaji!!!" << std::endl;
return 0;
}
int max_cool = 0;
int iB = M-1;
for (int iA = 0; iA < N; ++iA) {
while (iB >= 0 && (a[iA] + b[iB] > C)) {
iB--;
}
if (iB < 0) break;
int cool = iA + iB;
if (cool > max_cool) max_cool = cool;
}
std::cout << max_cool << std::endl;
return 0;
}
Related
Here is the problem-
You are given array B of size n. You have to construct array A such that 1<=A[i]<=B[i] and sum of the absolute difference of consecutive pairs of A is maximized ,that is, summation of abs(A[i]-A[i-1]) is maximised.You have to return this cost.
Example B=[1,2,3] A can be [1,2,1],[1,1,3],[1,2,3] In all these cases cost is 2 which is the maximum.
Constraints n<=10^5 ,1<=B[i]<=100
Here is my approach -
Cost will be maximum when A[i]=1 or A[i]=B[i]
So I created dp[idx][flag][curr] of size [100002][2][102] where it calculates the cost till index idx. flag will be 0 or 1 representing if A[i] should be 1 or B[i] respectively. curr will be the value of A[i] depending upon flag
Here is my code
#include<bits/stdc++.h>
using namespace std;
#define boost ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
typedef long long int ll;
#define mod 1000000007
ll n;
ll dp[100002][2][101];
ll b[100005];
ll solve(ll idx,ll flag,ll curr)
{
if(idx>=n)
return 0;
ll s1=0;
if(dp[idx][flag][curr]!=-1)
return dp[idx][flag][curr];
if(idx==0)
{
int left=solve(idx+1,0,curr);
int right=solve(idx+1,1,curr);
return dp[idx][flag][curr]=max(left,right);
}
else
{
if(flag==0)
{
s1=abs(curr-1);
return dp[idx][flag][curr]=s1+max(solve(idx+1,0,1),solve(idx+1,1,1));
}
else
{
s1=abs(b[idx]-curr);
return dp[idx][flag][curr]=s1+max(solve(idx+1,0,b[idx]),solve(idx+1,1,b[idx]));
}
}
}
int main()
{
boost
ll t;
cin>>t;
while(t--)
{
cin>>n;
memset(dp,-1,sizeof(dp));
ll res=0;
for(int i=0;i<n;i++)
cin>>b[i];
ll s1=solve(0,0,1);//Starting from idx 0 flag 0 and value as 1
ll s2=solve(0,1,b[0]);//Starting from idx 0 flag 1 and value as B[0]
cout<<max(s1,s2)<<"\n";
}
}'
Is there any way to reduce states of dp or any other top down solution because my code fails if values of B[i] are large
You implement a recursive approach. Here, a simple iterative implementation allows to get a time efficiency of O(n) and a space efficiency of O(1)
(not counting the space needed for the input array).
You correctly stated that at index i, we have two choices only, a[i]=1 (flag = 0) or a[i]=b[i] (flag = 1)
The basic idea is that, when studying what choice to make at index i, we only need to know what are the optimum sums ending at index i-1, for flag = 0 (sum0) or flag = 1 (sum1).
We don't need to explicitely calculate the array a[.].
Note: I kept long long int as in your code, but it seems that int is quite enough here.
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <algorithm>
#define mod 1000000007 // needed ???
long long int sum_diff (const std::vector<long long> &b) {
int n = b.size();
long long int sum0 = 0;
long long int sum1 = 0;
for (int i = 1; i < n; ++i) {
long long int temp = std::max (sum0, sum1 + b[i-1] - 1); // flag = 0: a[i] = 1
sum1 = std::max (sum0 + b[i] - 1, sum1 + std::abs(b[i] - b[i-1])); // flag = 1: a[i] = b[i]
sum0 = temp;
}
return std::max (sum0, sum1);
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int t;
std::cin >> t;
while(t--) {
int n;
std::cin >> n;
std::vector<long long int> b(n);
for(int i = 0;i < n; i++) std::cin >> b[i];
long long int s = sum_diff (b);
std::cout << s << "\n";
}
}
As you insist to have a top-down (recursive) aproach, I have implement both approaches in the following code. But I insist that the iterative solution is better in this case.
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <algorithm>
int sum_diff (const std::vector<int> &b) {
int n = b.size();
int sum0 = 0;
int sum1 = 0;
for (int i = 1; i < n; ++i) {
int temp = std::max (sum0, sum1 + b[i-1] - 1); // flag = 0: a[i] = 1
sum1 = std::max (sum0 + b[i] - 1, sum1 + std::abs(b[i] - b[i-1])); // flag = 1: a[i] = b[i]
sum0 = temp;
}
return std::max (sum0, sum1);
}
void sum_diff_recurs (const std::vector<int> &b, int i, int&sum0, int &sum1) {
if (i == 0) {
sum0 = sum1 = 0;
return;
}
sum_diff_recurs (b, i-1, sum0, sum1);
int temp = std::max (sum0, sum1 + b[i-1] - 1); // flag = 0: a[i] = 1
sum1 = std::max (sum0 + b[i] - 1, sum1 + std::abs(b[i] - b[i-1])); // flag = 1: a[i] = b[i]
sum0 = temp;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int t;
std::cin >> t;
while(t--) {
int n, sum0, sum1;
std::cin >> n;
std::vector<int> b(n);
for(int i = 0; i < n; i++) std::cin >> b[i];
int s = sum_diff (b);
std::cout << s << "\n";
sum_diff_recurs (b, n-1, sum0, sum1);
std::cout << std::max(sum0, sum1) << "\n";
}
}
Actually I found the solution using only two states idx and flag
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
ll n,k;
ll dp[100002][2];
ll b[100005];
ll solve(ll idx,ll flag)
{
if(idx>=n-1)
return 0;
if(dp[idx][flag]!=-1)
return dp[idx][flag];
ll val=(flag==1)?b[idx]:1;
ll left=solve(idx+1,0)+val-1;
ll right=solve(idx+1,1)+abs(val-b[idx+1]);
return (dp[idx][flag]=max(left,right));
}
int main()
{
ll t;
cin>>t;
while(t--)
{
cin>>n;
memset(dp,-1,sizeof(dp));
ll res=0;
for(int i=0;i<n;i++)
cin>>b[i];
ll s1=solve(0,0);
ll s2=solve(0,1);
cout<<max(s1,s2)<<"\n";
}
}
I was making an algorithm to solve Problem 1310 from the URI Online Judge and at some point i needed to delete an item from an array in an easy way, so i declared a vector, but, besides having no issues running whatsoever, my code doesn´t print anything using , cout doesn´t work at all.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int Lucro(int c, int n, vector<int> r){
if (n == 0){
return 0;
}else if (n == 1){
return max(r[0] - c, 0);
}
int q;
q = 0;
for (int k = 0; k < n; k++){
r.erase(r.begin() + k);
q = max(q, r[k] - c + Lucro(c, n-1, r));
}
return q;
}
int main()
{
int C, N, items;
cin >> N >> C;
vector<int> R;
for (int i = 0; i < N; i++){
cin >> items;
R.push_back (items);
}
cout << Lucro(C, N, R) << endl;
cout << 'test' << endl;
}
As i´m quite new to using vectors in c++, could someone please explain to me what´s going on and how to fix it?
Most likely your program crashes because you are getting out-of-range of your vector by erasing elements and not decrementing the size n:
for (int k = 0; k < n; k++){
r.erase(r.begin() + k); //decrement n after this
q = max(q, r[k] - c + Lucro(c, n-1, r));
}
In any case you shouldn't really have n variable at all, you should use r.size() to always get the current size of the vector.
I am trying to solve the Non-Divisible Subset problem from Hackerrank (https://www.hackerrank.com/challenges/non-divisible-subset). I am trying to use the idea that if the sum of a and b is divisible by k, then a%k+b%k = k, however, it's not working very well.
Here is what I've written so far:
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int n;
int k;
cin >> n;
cin >> k;
int j;
vector<int>numbers;
vector<int>remainders;
for(int i = 0; i < n; i++) {
int z;
cin >> z;
numbers.push_back(z);
}
for (vector<int>::iterator it = numbers.begin(); it != numbers.end(); it++) {
j = *it % k;
remainders.push_back(j);
}
for(vector<int>::iterator it2 = remainders.begin(); it2 != remainders.end(); it2++) {
int remainderCount = 0;
int otherRemainderCount = 0;
otherRemainderCount = std::count(remainders.begin(), remainders.end(), k-*it2);
remainderCount = std::count(remainders.begin(), remainders.end(), *it2);
if (remainderCount > otherRemainderCount) {
theChosenOne = *it2;
} else if (otherRemainderCount > remainderCount) {
theChosenOne = k-*it2;
}
cout << theChosenOne << endl;
}
return 0;
}
I created a vector for the remainders and I am using the std::cout function to find out which remainder appears more in the vector. If K would be 5, *it2 = 4, and k-*it2 = 1. If *it2 appears more times, then I would choose *it2. Otherwise, I would choose k-*it2.
Your solution looks to be on the right track, but there is some change that is needed.
You basically need to hash the numbers in the array to proper location.
Have an array rem[k] initialised to 0.
Iterate over the n numbers in the array, and do the following:
rem[array[i]%k]++;
Now you have to deal with only the rem[] array, to find the maximum subset. The rem array has size of maximum k<=100. Make use of the small size of rem[] array to find the solution efficiently.
Edit: Adding the code for you.
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int n,i,k;
cin>>n>>k;
int arr[n];
int rem[k]={0};
for(i=0;i<n;i++)
{
cin>>arr[i];
}
for(i=0;i<n;i++)
{
rem[arr[i]%k]++;
}
int count = 0;
for(i=1;i<=k/2;i++)
{
count = count + max(rem[i],rem[k-i]);
}
count = count + (rem[0]>0?1:0);
if(k%2==0)
{
count = count - rem[k/2];
if(rem[k/2]>0)
count = count + 1;
}
cout<<count;
return 0;
}
After you have found out the contents of the rem[] array, its time to find the maximum subset. If you select rem[1] then you cannot select rem[k-1] as any two numbers, one from rem[1] and another from rem[k-1] can be summed together which will be divisible by k that we don't want. So we find whichever is maximum out of rem[i] and rem[k-i] and add it to the count
My code uses the above logic..
Hope it helps!!!
int main() {
int n,k;
cin>>n>>k;
vector <int> a(n);
vector <int> r(k,0);
for(int i=0;i<n;i++)
{
cin>>a[i];
r[a[i]%k]++;
}
int ctr=min(1,r[0]);
for(int a=1;a<(k/2+1);a++)
{
if(a!=k-a)
ctr+=max(r[a],r[k-a]);
}
if(k%2==0&&r[k/2]!=0)
ctr++;
cout<<ctr;
return 0;
}
This seemed to work
#include <stdio.h>
int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }
int main() {
int n, k, a, total = 0;
scanf("%d %d", &n, &k);
int mods[k];
for (int i = 0; i < k; i++)
mods[i] = 0;
while (n--) {
scanf("%d", &a);
mods[a % k]++;
}
// can only have 1 value congruent to 0 mod k
total += min(1, mods[0]);
// if even, can only have 1 value congruent to k/2 mod k
if (k % 2 == 0)
total += min(1, mods[k / 2]);
// for all others, pick max of those k and n-k mod k
for (int d = 1; d < (k + 1) / 2; d++) { // for all others,
total += max(mods[d], mods[k - d]);
}
printf("%d", total);
return 0;
}
How can I solve this problem without getting time limit exceeded
http://codeforces.com/problemset/problem/474/B
I tried putting all ranges in a 2D vector then looking for the desired index using binary search but it seems that the loop in the fn BS() takes a lot to execute as the size of the vector can be 10^6.
here is my code:
#include <iostream>
#include <vector>
using namespace std;
int Search(vector <vector<int> > a,int key){
int start = 0;
int end = a.size() - 1;
while (start <= end){
int mid = start + (end - start) / 2;
if (a[mid][0] > key && a[mid][1] > key){
end = mid - 1;
}
else if (a[mid][0] < key && a[mid][1] < key){
start = mid + 1;
}
else {
return mid;
}
}
return -1;
}
vector <int> BS(vector <vector <int> > v, vector<int> keys){
int j = 0;
vector <int> piles;
for (int i = 0; i < keys.size(); i++){
piles.push_back(Search(v, keys[i])+1);
}
return piles;
}
vector < vector<int> > Range(vector<int> v){
vector < vector<int> > ranges(v.size());
int sum1 = 1;
int sum2 = v[0];
for (int i = 0; i < v.size(); i++){
if (i == 0){
ranges[i].push_back(sum1);
ranges[i].push_back(v[i]);
sum1 += v[i];
}
else{
ranges[i].push_back(sum1);
sum2 += v[i];
ranges[i].push_back(sum2);
sum1 += v[i];
}
}
return ranges;
}
int main(){
int n, m;
cin >> n;
vector <int> a, q;
vector < vector <int> > v;
for (int i = 0; i < n; i++){
int k;
cin >> k;
a.push_back(k);
}
cin >> m;
for (int i = 0; i < m; i++){
int l;
cin >> l;
q.push_back(l);
}
v = Range(a);
vector <int> jucy = BS(v, q);
for (int i = 0; i < jucy.size(); i++){
cout << jucy[i] << endl;
}
}
In fact i don`t think you need 2D vector at all, you need just 1D. Which for example would look like this [2,9,12,16,25], the upper bound of each pile, you can construct this really easy. Then for every juicy worm you do binary search in that manner that it returns index with value greater or equal to the value you are looking for. The index you got from the search is the pile you are looking for.
Some pseudo-code:
A[n] - vector of upper bounds
A[0] = a0
For each 0<i<=n A[i]=A[i-1]+ai
For each q do std lower_bound on A looking for q,
the index you get is with first value equal or greater than q, so the pile where is q.
and C++ code:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
int n, m;
cin >> n;
vector<int>A;
A.resize(n);
int ai;
cin >> ai;
A[0]=ai;
for (int i = 1; i < n; i++){
cin >> ai;
A[i]=A[i-1]+ai;
}
cin >> m;
int q;
for (int i = 0; i < m; i++){
cin >> q;
cout << std::distance(A.begin(),std::lower_bound(A.begin(),A.end(),q))+1<<endl;
}
return 0;
}
You have to add +1 to distance because the piles are numbered from 1. Work for the example, and looks pretty fast.
The most obvious optimization opportunity is, instead of using a vector<vector<int>> use a vector<int> and manually adjust the 2D indices to 1D. You can write a simple wrapper class that does this for you.
The reason that that will be much faster is that then all the memory will be allocated as a single contiguous unit. If you have a vector of vectors, then each row will be somewhere else and you'll have lots of cache misses.
Here's a code example:
struct 2D_Vector {
std::vector<int> me_;
int ncols_;
2D_Vector(int nrows, int ncols) : me(nrows * ncols), ncols_(ncols) {}
int & get(int y, int x) { return me_[y * ncols_ + x]; }
const int & get(int y, int x) const { return me_[y * ncols_ + x]; }
...
};
If you preallocate this with all the space that it will need, then it should use memory very efficiently.
Also, passing large function parameters by value instead of by reference is very wasteful, because it results in needless copies being made and destroyed. (Like WhozCraig pointed out.)
Following code runs correctly when the size of array below 40, but larger size makes it run very long time.
please tell me why it work like this. Thank you very much.
why the website always tells me to add some more details.
here is my code
#include<iostream>
using namespace std;
int Quicksort(int arr[], int l, int r) {
int p = arr[l];
int i = l+1;
for (int j = l+1; j <=r; j++){
if (arr[j] < p){
int tem = arr[i];
arr[i] = arr[j];
arr[j] = tem;
i +=1;
}
}
arr[l] = arr[i-1];
arr[i-1] = p;
int count = r-l;//each subarray has (r-l) comparisons
if (r-l ==0){
return 0;
}else{
int j =i-1;
if (j>l){
Quicksort(arr, l,j-1);
count +=Quicksort(arr,l,j-1);
}
if (j <r){
Quicksort(arr, j+1,r);
count += Quicksort(arr, j+1,r);
}
}
return count;
}
int main(){
int n;
cin >>n;
int arr[n];
for (int i = 0; i<n; i++){
cin >>arr[i];
}
cout<<Quicksort(arr, 0, n-1)<<endl;
for (int i = 0; i<n; i++){
cout << arr[i] <<' ';
}
cout <<endl;
return 0;
}
You are using the leftmost element of the partition as your pivot. This has a worst case scenario when the array is already sorted.
"But my array isn't already sorted!" you say. Well, look at these lines of code:
if (j <r){
Quicksort(arr, j+1,r);
count += Quicksort(arr, j+1,r);
}
You are calling QuickSort twice, the second time you call it, the partition is already sorted. Leading to a worst case scenario for the second call.
Your two consecutive calls to Quicksort with the same arguments and poor choice of pivot will result in exponential runtime. It can be tricky to write a good Quicksort algorithm, but there are excellent algorithm texts, such as by Robert Sedgewick, which have good implementations of Quicksort.
On the other hand, you can use the generic sort algorithm provided by the C++ STL.
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
int n;
cin >> n;
vector<int> arr;
for (int i = 0; i < n; i++) {
int val;
cin >> val;
arr.push_back(val);
}
sort(arr.begin(), arr.end());
for (int x : arr)
cout << x << ' ';
cout << endl;
return 0;
}