Google Code Jam Minimum Scalar Product - c++

I was solving a problem from Google Code Jam and I am not able to solve the problem: http://code.google.com/codejam/contest/32016/dashboard#s=p0 (Minimum Scalar Product, Problem A 2008)
The strategy I used was:
Accept v1 and v2 from the user
Sort both v1 and v2
Reverse v2 i.e. sort v2 in descending order
Multiply straight-out corresponding v1[i] * v2[i] and store the result in product
Sum up all such products and print the answer
I did some research and indeed it appears that's the only permutation that's possible to obtain. However, my code does not produce the correct output:
#include <stdio.h>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
int T;
int cases;
FILE *fin = fopen ("A-small-practice.in", "r"); // open input file
FILE *fout = fopen ("output.out", "w");
fscanf(fin, "%d", &T);
for(cases = 1; cases <= T; cases++)
{
int v1[1000], v2[1000];
int i,j; int n;
int product =0;
fscanf(fin, "%d", &n);
for(i=0; i < n; i++)
{
fscanf(fin, "%d",&v1[i]);
fscanf(fin, "%d", &v2[i]);
}
sort(v1,v1+n);
sort(v2,v2+n);
reverse(v1, v1+n);
int k;
for(k = 0; k < n; k++)
{
product += v1[k] * v2[k];
}
fprintf(fout, "Case #%d: %d\n", cases, product);
}
return 0;
}

You should use long long.
This worked for me:
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
long long T,n,v1[1000],v2[1000];
cin >> T;
for (int t = 1; t <= T; t++) {
cin >> n;
for (int i = 0; i < n; i++)
cin >> v1[i];
for (int i = 0; i < n; i++)
cin >> v2[i];
sort(v1,v1+n);
sort(v2,v2+n);
long long p = 0;
for (int i = 0; i < n; i++)
p += v1[i]*v2[n-i-1];
cout << "Case #" << t << ": " << p << endl;
}
return 0;
}

After hours of troubleshooting, I found that the problem was in the way input was taken, as I had used only one loop for both v1 & v2:
for(i=0; i < n; i++)
{
fscanf(fin, "%d",&v1[i]);
fscanf(fin, "%d", &v2[i]);
}
And it should have been done this way:
for(i=0; i<n; i++)
fscanf(fin, "%d",&v1[i]);
for(i=0; i<n; i++)
fscanf(fin, "%d", &v2[i]);
Thank you lukas1994 and pkacprzak

This worked for me:
#include <algorithm>
#include <iostream>
#include <vector>
#include <numeric>
using std::vector;
long long min_dot_product(size_t n, vector<int> a, vector<int> b) {
long long result = 0;
if (n != 0)
{
std::sort(a.begin(), a.end());
std::sort(b.begin(), b.end());
std::reverse(a.begin(), a.end());
/*for (size_t i = 0; i < n; i++) {
result += a[i] * b[n - 1 - i];
}*/
result = std::inner_product(a.begin(), a.end(), b.begin(), 0);
}
return result;
}
int main() {
size_t n;
std::cin >> n;
vector<int> a(n), b(n);
for (size_t i = 0; i < n; i++) {
std::cin >> a[i];
}
for (size_t i = 0; i < n; i++) {
std::cin >> b[i];
}
std::cout << min_dot_product(n, a, b) << std::endl;
}

There is a specific case to be considered.
When one vector is all negative and the other all positive, the algorithm does not produce the minimum result.
if x = [-1,-2] and x = [1,2]
the minimum according to the algorithm output is :
(-1*2) + (-2*1) = -4
However, if you instead use x1y1 + x2y2... xnyn for this case you get:
(-1 * 1) + ( -2*2) = -1-4 = -5

Related

Time limit exceeded on codeforces

I've been stuck on this problem for a pretty Long while. I always get "Time limit exceeded" when I submit the code.
My solution is to input the items of the array then determine the largest number in the array and diplay it along with the elements following it and so on.
How can I make my algorithm more efficient?
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int T, n;
cin >> T;
while (T--) {
//inputting p[n]
scanf_s("%d", &n);
int* p = new int[n];
for (int i = 0; i < n; i++) {
scanf_s("%d", &p[i]);
}
while (n != 0) {
//*itr = largest element in the array
auto itr = find(p, p + n, *max_element(p, p + n));
int index = distance(p, itr);
for (int i = index; i < n; i++) {
printf("%d\n", p[i]);
}
//deleting element by decreasing n:
n = index;
}
delete[] p;
}
return 0;
}
You solution is O(n^2), too slow.
A O(n) solution is obtained by iteratively calculating the position of the max element until a given index i.
#include <iostream>
#include <vector>
#include <algorithm>
//using namespace std;
int main() {
int T;
std::cin >> T;
while (T--) {
//inputting p[n]
int n;
std::cin >> n;
std::vector<int> p(n);
for (int i = 0; i < n; i++) {
std::cin >> p[i];
}
std::vector<int> max_before(n);
max_before[0] = 0;
for (int i = 1; i < n; ++i) {
if (p[i] > p[max_before[i-1]]) {
max_before[i] = i;
} else {
max_before[i] = max_before[i-1];
}
}
while (n != 0) {
int index = max_before[n-1];
for (int i = index; i < n; i++) {
std::cout << p[i] << " ";
}
//deleting element by decreasing n:
n = index;
}
std::cout << '\n';
}
return 0;
}

How do I resolve sigabrt error on codechef ide

Sigabrt runtime error occurs of a fatal error, because of an assert statement not returning true? Or use of excessive memory, I'm not able to figure out what I'm doing wrong here, help me out?
( problem 1343 C on codeforces) link
so here's the code.
#include <iostream>
#include <stdlib.h>
#include<vector>
using namespace std;
int check(int i,vector<int> a) {
if (a[i] > 0) {
return 1;
}
else return 0;
}
int main() {
int t;
cin >> t;
while (t--)
{
long int n;
cin >> n;
vector<int> a(n), b;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
int i = 0;
while (i < n)
{
int max = a[i];
int s = check(i,a);
i++;
while (i<n && check(i,a)== s) {
if (a[i] > max)max = a[i];
i++;
}
b.push_back(max);
}
int s = 0;
for (int k = 0; k< b.size(); k++) {
s += b[i];
}
cout << s << endl;
}
}
I have debugged your code and also the modified code has been accepted for the above question.
Mistakes you made:
1. In the below loop, value at i'th index of vector<int> b is being added to long int s. Instead, b[k] should be added to long int s because the variable being used in the loop is k not i.
for (int k = 0; k< b.size(); k++) {
s += b[i];
}
2. In the question, range of variable n is given as (1 ≤ n ≤ 2.10^5). So, it is safe to use int n instead of long int n. Also, when I submitted my code on codeforces it gave me signed integer overflow error when I used long int n.
3. You need to use long long s instead of long int s because the value of each element of array A lies between (−10^9 ≤ a[i] ≤ 10^9 , ai ≠ 0) and when we add the elements it can easily surpass int and long int ranges.
4. Although, the answer got accepted when I used vector<int> a in the function
int check(int i,vector<int> a) {
if (a[i] > 0) {
return 1;
}
else return 0;
}
But as the user Scheff has said and is correct that it comes with a penalty in space and time, you should use call by reference i.e. vector<int> &a.
Modified Code:
#include <iostream>
#include <stdlib.h>
#include<vector>
using namespace std;
int check(int i, vector<int> &a) {
if (a[i] > 0) {
return 1;
}
else return 0;
}
int main() {
int t;
cin >> t;
while (t--)
{
int n;
cin >> n;
vector<int> a(n), b;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
int i = 0;
while (i < n)
{
int max = a[i];
int s = check(i,a);
i++;
while ((i<n) && (check(i,a)== s)) {
if (a[i] > max)
max = a[i];
i++;
}
b.push_back(max);
}
long long s = 0;
for (int k = 0; k< b.size(); k++) {
s += b[k];
}
cout << s << endl;
}
}
Screenshot of Accepted Answer:

removing double elements in an array

I am trying to remove double elements in an array. I developed a simple code, but it is still not working. Is it possible to hint for some input maybe I haven't tried. I tried corner and test cases. The following is the problem statement:
A sequence of numbers given. Remove element’s doubles, leaving first copy.
Input: Contains a natural n (n ≤ 100000) – the n quantity numbers in a sequence, then n non-negative numbers – elements of the sequence which module is not greater than 999.
output: changed sequence.
It seems I can't get what might be the problem
#include <iostream>
//#include <cmath>
//#include <climits>
#define SIZE 100000
using namespace std;
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int n, k, p;
bool tag; tag = false;
cin >> n;
long long int *a = new long long int[n];
long long int b[SIZE];
for (int i = 0; i < n; i++) { cin >> a[i]; }
for (int i = 0; i < n; i++) { k = 0;
for (int j = i + 1; j < n; j++) {
if (a[i] == a[j]) { b[k] = j-k; k++; tag = true; }
}
if (tag) {
for (int i = 0; i < k; i++) {
p = b[i];
for (int i = p; i < n; i++) { a[i] = a[i + 1]; }
n--;
}
tag = false;
}
}
for (int i = 0; i < n; i++) { cout << a[i] << " "; }
return 0;
}
Input: 6 1 2 2 4 3 4 Output: 1 2 4 3
You can use unordered_set and vector
int n; cin >> n;
long long int x;
unordered_set<long long int>myset;
vector<long long int>v1;
for (int i = 0; i < n; i++)
{
cin>>x;
if(myset.find(x)==myset.end())
{
myset.insert(x);
v1.push_back(x);
}
}
for(int i=0;i<v1.size();i++)
{
cout<<v1[i]<<" ";
}
You could use in you advantage the fact that input values are in the range from 0 to 999.
A simple bool used[1000]{} could be used to flag if the current value has been used already before pushing it to cout, thus ensuring both O(n) complexity and limited memory usage (1000 bytes for the bool[]}.
Here's a sample solution around this idea:
#include<iostream>
#define MAX_VALUE 999
using namespace std;
int main() {
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
bool used[MAX_VALUE + 1]{};
size_t n;
cin >> n;
for (size_t num, i = 0; i < n; ++i) {
cin >> num;
if (!used[num]) {
cout << num << " ";
used[num] = true;
}
}
return 0;
}
You could try creating a second array of unique numbers as you go. I will demonstrate with a vector for the sake of simplicity.
std::vector<int> v;
for (int i = 0; i < n; i++) {
if (std::find(v.begin(), v.end(), arr[i]) == v.end()) {
v.push_back(arr[i]);
}
}
Then, you just write the contents of the vector to the output file.
Here is my version of O(n) complexity. Your solution may exceed time-limit ( if it is low )
bool check[2000];
for (int i = 0; i < 2000; i++) check[i] = 0;
for (int i = 0; i < n; i++) {
cin >> a[i];
// +999 to avoid negative numbers
check[a[i] + 999] = 1;
}
bool isPrint = false;
for (int i = 0; i < n; i++) {
if (check[a[i] + 999]) {
// mark false if already printed
check[a[i] + 999] = 0;
if (isPrint) printf(" ");
printf("%d", a[i]);
isPrint = true;
}
}

I want to print the following pattern

1
3 2
6 5 4
10 9 8 7
I want to print the following pattern. I have tried very hard but couldn't make the code for it. I have tried everything which came up to my mind.
#include<iostream>
using namespace std;
int main() {
int i, j, n;
cin >> n;
int k = 0;
for (i = 1;i <= n; i++) {
for (j = 1; j <= i; j++) {
k++;
printf("%d ", k);
}
printf("\n");
}
}
the other code which i tried is this.
#include<iostream>
using namespace std;
int main() {
int i, j, n;
cin >> n;
int k = 0;
for (i = 1; i <= n; i++) {
for (j = i; j >= 1; j--) {
k++;
printf("%d ",j);
}
printf("\n");
}
}
#include <iostream>
#include <stack>
using namespace std;
int main()
{
int previousRow = 0;
for(int row = 1; row <= 4; row++)
{
int rowTracker = row;
for(int col = 0; col < row; col++)
{
cout<<rowTracker - col + previousRow<<" ";
}
previousRow += row;
cout<<endl;
}
return 0;
}
#include<iostream>
void printPattern(unsigned numlevels)
{
unsigned last_num = 1;
for(unsigned i = 0; i < numlevels; ++i)
{
unsigned next_num = i + last_num;
for(unsigned j = next_num; j >= last_num; --j)
{
std::cout << j << ' ';
}
std::cout << '\n';
last_num = next_num + 1;
}
}
int main()
{
unsigned n;
std::cin >> n;
printPattern(n);
return 0;
}
You may also use a stack to implement this. Here is a working answer:
#include <iostream>
#include <stack>
using namespace std;
int main() {
int i, j, n;
stack<int> st;
cin >> n;
int k = 0;
for(i = 1;i <= n; i++) {
for(j = 1; j <= i; j++) {
k++;
st.push(k);
}
while(!st.empty()){
printf("%d ", st.top());
st.pop();
}
printf("\n");
}
}
Hope it helps!
Before reading the code blow, you should really try to do it yourself. This problem is obviously for practice and to develop the programming muscle. Just getting the answer is not going to help.
The issue with your code is that for each row, the range you want to print is not being determined correctly. You should first find the range and then print the numbers. Ther can be multiple approaches to it. Below is one of them.
for(i=1;i<=n;i++){
int max = i*(i+1)/2;
int min = i*(i-1)/2 + 1;
for(j=max;j>=min;j--){
printf("%d ",j);
}
printf("\n");
}
Here is a simple method
int main(int argc, char* argv[])
{
int n = 4; // suppose print 4 lines
for (int i = 1; i <= n; ++i)
{
int i0 = (i + 1) * i / 2; // first number of line i
for (int j = 0; j < i; j++)
cout << i0 - j << " ";
cout << endl;
}
return 0;
}
thanx everyone for your responses. I was able to do it on my own. Below is what I did. if there is any correction let me know
#include<iostream>
using namespace std;
int main(){
int i,j,n,temp;
cin>>n;
int k=0;
for(i=1;i<=n;i++){
k=k+i,temp=k;
for(j=1;j<=i;j++){
cout<<temp<<+" ";
temp--;
}
cout<<("\n");
}
}

Having trouble implementing pseudocode for Subset Sum

so I am trying to implement the following pseudocode but it will not work as it is supposed to. Here is the problem description in the slide, "Given an integer bound, "W", and a collection of "n" items, each with a positive integer weight "wi", find a subset S of items that: maximizes Sigma sub i where i is an element of S "wi" while keeping this sum less than or equal or to W. I will attach the following slides for where I am getting the problem description and pseudocode from. The problem with my implementation is that it will only find the total max value and not the value that is less than or equal to the weight. So for example, if I had Weight 10 (W = 10) and items 3 (n = 3) with item weights 1, 4, & 8 then the following answer should be 9; however, my solution gives 12. Here are the slides (*Please not, where it says w[j] it is meant to be w[i] - the slide had a typo):
Here is my code that implements the pseudocode:
#include <stdio.h>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int max(int a, int b, int c) {
if (a >= b)
return a;
else
return b;
}
int optimal_weight(int W, const vector<int> &wt, int n){
vector<vector<int> > M;
M.resize(n+1);
for(int i = 0; i < n+1; ++i){
M[i].resize(W+1);
}
for(int w = 0; w < W+1; w++){
M[0][w] = 0;
}
for(int i = 1; i < n+1; i++){
M[i][0] = 0;
}
for(int i = 1; i < n+1; i++){
for(int w = 0; w < W+1; w++){
if(wt[i] > w){
M[i][w] = M[i-1][w];
}
M[i][w] = max(M[i-1][w], wt[i] + M[i-1][W-wt[i]], W);
}
}
for (int i = 0; i <= n; i++)
{
for (int j = 0; j <= W; j++)
printf ("%4d", M[i][j]);
printf("\n");
}
return M[n][W];
}
int main()
{
//int val[] = {1, 1, 1};
int W;
int n;
cin >> W >> n;
vector<int> wt(n);
for(int i = 0; i < n; i++){
cin >> wt[i];
}
cout << optimal_weight(W, wt, n) << endl;
}
Thank you for any help!
I figured it out! Here is my solution:
#include <iostream>
#include <vector>
using namespace std;
using std::vector;
int optimal_weight(int W, const vector<int> &wt) {
//write your code here
int n = wt.size();
vector<vector<int> > matrix;
matrix.resize(W+1);
for(int i = 0; i < W+1; i++){
matrix[i].resize(n);
}
for(int j = 0; j < n; j++){
matrix[0][j] = 0;
}
for(int w = 0; w < W + 1; w++){
matrix[w][0] = 0;
}
for(int i = 1; i < n; i++){
for(int w = 1; w < W+1; w++){
matrix[w][i] = matrix[w][i-1];
if(wt[i] <= w){
//cout << wt[i] << endl;
int val = matrix[w-wt[i]][i-1] + wt[i];
if(matrix[w][i] < val){
matrix[w][i] = val;
}
}
}
}
return matrix[W][n-1];
}
int main() {
int n, W;
std::cin >> W >> n;
vector<int> wt(n+1);
for (int i = 1; i < n+1; i++) {
wt[0]=0;
std::cin >> wt[i];
}
std::cout << optimal_weight(W, wt) << '\n';
}