TIME_LIMIT_EXCEEDED at Codeforces 558E - c++

I am beginner in the programming field and I have started to solve problems on Codeforces and this is my first problem on it and when I submit this problem solution A Simple Task with this code
#include <iostream>
#include <string>
using namespace std;
void swapchar(char &x, char &y)
{
char temp;
temp = x;
x = y;
y = temp;
}
void main()
{
string s;
long n, q;
long i, j;
bool k;
cin >> n >> q;
cin >> s;
for (int x = 0; x<q; x++)
{
cin >> i >> j >> k;
if (i<1 || j<1 || i>n || j>n)
break;
if (k == 1)
{
for (int u = i - 1; u < j; u++)
{
for (int v = u + 1; v < j; v++)
{
if (s[u] > s[v])
swapchar(s[u], s[v]);
}
}
}
else if (k == 0)
for (int u = i - 1; u < j; u++)
{
for (int v = u + 1; v < j; v++)
{
if (s[u] < s[v])
swapchar(s[u], s[v]);
}
}
}
cout << s << endl;
}
then the codeforces' output is :-
Time limit exceeded on test 6
and when i searched about what it is the test 6 i found :-
Test: #6, time: 5000 ms., memory: 12 KB, exit code: -1, checker exit code: 0, verdict: TIME_LIMIT_EXCEEDED
Input
2256 44182
kanqevxwgecliptqmdsgnflqyohgtukphlbmjxndbtjqujuafxankfghlseytdwdviamqjscacuyrghriuaihxtyersgnyvigenpflwequgbdusnvlgplxjxkqhjbdvkmufpoirqueufblnnrnbhmcnvewzfdonwjgswuneimtykntwgrlfqlvkdblwjzplhffzqpopbjmvrjcxyzgxqhkjbrgdqnipsipexpoozphfrgzboiiiskawtbhegerhvknrzljclhnpokpazhspsmzeiujddlpfireoyjzriickcuwtbimxjbhunedcdgaabztczkzmahnriarzcmnkjrrfqkodxbpocmxjvutpqbmawcsghwxdidhmwbfxuqegpjtqfvaloycogvoxdtjotlknazaeofaxlomeywwlezlndhpjwbgpxgkvubropxffytucvlbhjugzqgglrezoqsrvwkdrbuehbjxtgobugghqrgbgacqi...
I don't know what does that problem mean and how to solve it
Please explain and help me.

You're using a selection sort (with a few superfluous swaps) that's O(n^2) complexity, try using std::sort instead. You don't have too much to change in your code:
#include <iostream>
#include <string>
#include <algorithm>
#include <functional>
using namespace std;
int main()
{
string s;
long n, q;
long i, j;
bool k;
cin >> n >> q;
cin >> s;
for (int x = 0; x<q; x++)
{
cin >> i >> j >> k;
if (i<1 || j<1 || i>n || j>n)
break;
if (k == 1)
{
std::sort(s.begin() + i-1, s.begin() + j);
}
else if (k == 0)
std::sort(s.begin() + i-1, s.begin() + j, std::greater<char>());
}
cout << s << endl;
}
std::sort(s.begin() + i-1, s.begin() + j); sorts from s.begin() + i-1 up to but not includings.begin() + j. The second just sorts in reverse order by using > (std::greater) instead of < for comparison. Note the #include <algorithm> for the std::sort and #include <functional> for std::greater.
Note that I got rid of your swapchar function since we don't need it anymore, I also changed the return type of main to int as it's supposed to be.
The above code manages to handle the test 6 that you had problems with but exceeds time limit for test 9 (I even tried some small other changes there).
To complete tests 9+ you're probably supposed to think a bit more about the problem and possible input, take for example the following sort queries:
20 57 1
89 950 1
57 100 0
57 100 1
1 9500 0
Here we'd do tons of useless sorting and I wouldn't be surprised if the 9th problem were to test if you identified this. First we sort the range [20, 57] and [89, 950] in ascending order, then we sort the range [57, 100] in descending order and resorting the same range in ascending order right afterwards overriding the first one completely. Lastly we sort the range [1, 9500] in descending order, overwriting all the previous sorts which we could have completely left out since they're overwritten anyways.
We could make use of the knowledge that later sorts can and likely will override previous ones. We could first save all the "sort queries" we were given and later start with the last one (since that one would override all previous ones anyways) and go in reverse order only sorting the ranges we haven't sorted yet. That way we can get rid of lots of useless sorting that we'd otherwise do even though we'd later overwrite it and speeding it up a lot.

Related

Minimum Cost to reduce the size of array to 1

Given an array of N numbers (not necessarily sorted). We can merge any two numbers into one and the cost of merging the two numbers is equal to the sum of the two values. The task is to find the total minimum cost of merging all the numbers.
Example:
Let the array A = [1,2,3,4]
Then, we can remove 1 and 2, add both of them and keep the sum back in array. Cost of this step would be (1+2) = 3.
Now, A = [3,3,4], Cost = 3
In second step, we can 3 and 3, add both of them and keep the sum back in array. Cost of this step would be (3+3) = 6.
Now, A = [4,6], Cost = 6
In third step, we can remove both elements from the array and keep the sum back in array again. Cost of this step would be (4+6) = 6.
Now, A = [10], Cost = 10
So, total cost turns out to be 19 (10+6+3).
We will have to pick the 2 smallest elements to minimize our total cost. A simple way to do this is using a min heap structure. We will be able to get the minimum element in O(1) and insertion will be O(log n).
The time complexity of this approach is O(n log n).
But I tried another approach, and wasn't able to find the cases where it fails. The basic idea was that the sum of two smallest elements that we will choose at any time will always be greater than the sum of the pair of elements chosen before. So the "temp" array will always be sorted, and we will be able to access the minimum elements in O(1).
As I am sorting the input array and then simply traversing the array, the complexity of my approach is O(n log n).
int minCost(vector<int>& arr) {
sort(arr.begin(), arr.end());
// temp array will contain the sum of all the pairs of minimum elements
vector<int> temp;
// index for arr
int i = 0;
// index for temp
int j = 0;
int cost = 0;
// while we have more than 1 element combined in both the input and temp array
while(arr.size() - i + temp.size() - j > 1) {
int num1, num2;
// selecting num1 (minimum element)
if(i < arr.size() && j < temp.size()) {
if(arr[i] <= temp[j])
num1 = arr[i++];
else
num1 = temp[j++];
}
else if(i < arr.size())
num1 = arr[i++];
else if(j < temp.size())
num1 = temp[j++];
// selecting num2 (second minimum element)
if(i < arr.size() && j < temp.size()) {
if(arr[i] <= temp[j])
num2 = arr[i++];
else
num2 = temp[j++];
}
else if(i < arr.size())
num2 = arr[i++];
else if(j < temp.size())
num2 = temp[j++];
// appending the sum of the minimum elements in the temp array
int sum = num1 + num2;
temp.push_back(sum);
cost += sum;
}
return cost;
}
Is this approach correct? If not, please let me know what I am missing, and the test cases in which this algorithm fails.
SPOJ Link for the same problem
The logic seems very solid to me... all the computed sums will never be decreasing and therefore you only need to add up either oldest two computed sums, next two elements or oldest sum and next element.
I would just simplify the code:
#include <vector>
#include <algorithm>
#include <stdio.h>
int hsum(std::vector<int> arr) {
int ni = arr.size(), nj = 0, i = 0, j = 0, res = 0;
std::sort(arr.begin(), arr.end());
std::vector<int> temp;
auto get = [&]()->int {
if (j == nj || (i < ni && arr[i] < temp[j])) return arr[i++];
return temp[j++];
};
while ((ni-i)+(nj-j)>1) {
int a = get(), b = get();
res += a+b;
temp.push_back(a + b); nj++;
}
return res;
}
int main() {
fprintf(stderr, "%i\n", hsum(std::vector<int>{1,4,2,3}));
return 0;
}
Very nice idea!
Another improvement is noting that the cumulative length of the two arrays being processed (the original one and the temporary one holding the sums) will decrease at every step.
Since the first step will use two input elements, the fact that the temporary array grows one element at each step will still not be enough for a "walking queue" allocated in the array itself to reach the reading pointer.
This means that there is no need of a temporary array and the space for the sums can be found in the array itself...
int hsum(std::vector<int> arr) {
int ni = arr.size(), nj = 0, i = 0, j = 0, res = 0;
std::sort(arr.begin(), arr.end());
auto get = [&]()->int {
if (j == nj || (i < ni && arr[i] < arr[j])) return arr[i++];
return arr[j++];
};
while ((ni-i)+(nj-j)>1) {
int a = get(), b = get();
res += a+b;
arr[nj++] = a + b;
}
return res;
}
About the error on SPOJ... I tried briefly to search for the problem but I didn't succeed. I tried however generating random arrays of random lengths and checking this solution with what finds a "brute-force" one implemented directly from the specs and I'm reasonably confident that the algorithm is correct.
I know at least one programming arena (Topcoder) where sometimes the problems are carefully crafted so that the computation gives correct results if using unsigned but not if using int (or if using unsigned long long but not if using long long) because of integer overflow.
I don't know if SPOJ also does this kind of nonsense(1)... may be that is the reason some hidden test case fails...
EDIT
Checking with SPOJ the algorithm passes if using long long values... this is the entry I used:
#include <stdio.h>
#include <algorithm>
#include <vector>
int main(int argc, const char *argv[]) {
int n;
scanf("%i", &n);
for (int testcase=0; testcase<n; testcase++) {
int sz; scanf("%i", &sz);
std::vector<long long> arr(sz);
for (int i=0; i<sz; i++) scanf("%lli", &arr[i]);
int ni = arr.size(), nj = 0, i = 0, j = 0;
long long res = 0;
std::sort(arr.begin(), arr.end());
auto get = [&]() -> long long {
if (j == nj || (i < ni && arr[i] < arr[j])) return arr[i++];
return arr[j++];
};
while ((ni-i)+(nj-j)>1) {
long long a = get(), b = get();
res += a+b;
arr[nj++] = a + b;
}
printf("%lli\n", res);
}
return 0;
}
PS: This very kind of computation is also what is needed to build an Huffman tree for entropy coding given the symbols frequency table and thus it's not a mere random exercise but it has practical applications.
(1) I'm saying "nonsense" because in Topcoder they never give problems that require 65 bits; thus it's not a genuine care about overflows, but just setting traps for novices.
Another that I think is a bad practice I saw on TC is that some problems are carefully designed so that the correct algorithm if using C++ will barely fit in the timeout limit: just use another language (and get e.g. a 2× slowdown) and you cannot solve the problem.
First of all, think simple!
When using a priority queue, the problem is easy!
In the first test case :
1 6 3 20
// after pushing to Q
1 3 6 20
// and sum two top items and pop and push!
(1 + 3) 6 20 cost = 4
(4 + 6) 20 cost = 10 + 4
(10 + 20) cost = 30 + 14
30 cost = 44
#include<iostream>
#include<queue>
using namespace std;
int main()
{
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
priority_queue<long long int, vector<long long int>, greater<long long int>> q;
for (int i = 0; i < n; ++i) {
int k;
cin >> k;
q.push(k);
}
long long int sum = 0;
while (q.size() > 1) {
long long int a = q.top();
q.pop();
long long int b = q.top();
q.pop();
q.push(a + b);
sum += a + b;
}
cout << sum << "\n";
}
}
Basically we need to sort the list in desc order and then find its cost like this.
A.sort(reverse=True)
cost = 0
for i in range(len(A)):
cost += A[i] * (i+1)
return cost

Unıque Random Number Check form Array c++

#include <iostream>
#include<ctime>
#include<cstdlib>
#include<string>
#include<cmath>
using namespace std;
int main()
{
bool cont = false;
string str;
int num, num2;
cin >> str >> num;
int arr[10];
int a = pow(10, num);
int b = pow(10, (num - 1));
srand(static_cast<int>(time(NULL)));
do {
num2 = rand() % (a - b) + b;
int r;
int i = 0;
int cpy = num2;
while (cpy != 0) {
r = cpy % 10;
arr[i] = r;
i++;
cpy = cpy / 10;
}
for (int m = 0; m < num; m++)
{
for (int j = 0; j < m; j++) {
if (m != j) {
if (arr[m] == arr[j]) {
break;
}
else {
cont = true;
}
}
}
}
cout << num2 << endl;
} while (!cont);
return 0;
}
I want to take a number from the user and produce such a random number.
For example, if the user entered 8, an 8-digit random number.This number must be unique, so each number must be different from each other,for example:
user enter 5
random number=11225(invalid so take new number)
random number =12345(valid so output)
To do this, I divided the number into its digits and threw it into the array and checked whether it was unique. The Program takes random numbers from the user and throws them into the array.It's all right until this part.But my function to check if this number is unique using the for loop does not work.
Because you need your digits to be unique, it's easier to guarantee the uniqueness up front and then mix it around. The problem-solving principle at play here is to start where you are the most constrained. For you, it's repeating digits, so we ensure that will never happen. It's a lot easier than verifying if we did or not.
This code example will print the unique number to the screen. If you need to actually store it in an int, then there's extra work to be done.
#include <algorithm>
#include <iostream>
#include <numeric>
#include <random>
#include <vector>
int main() {
std::vector<int> digits(10);
std::iota(digits.begin(), digits.end(), 0);
std::shuffle(digits.begin(), digits.end(), std::mt19937(std::random_device{}()));
int x;
std::cout << "Number: ";
std::cin >> x;
for (auto it = digits.begin(); it != digits.begin() + x; ++it) {
std::cout << *it;
}
std::cout << '\n';
}
A few sample runs:
Number: 7
6253079
Number: 3
893
Number: 6
170352
The vector digits holds the digits 0-9, each only appearing once. I then shuffle them around. And based on the number that's input by the user, I then print the first x single digits.
The one downside to this code is that it's possible for 0 to be the first digit, and that may or may not fit in with your rules. If it doesn't, you'd be restricted to a 9-digit number, and the starting value in std::iota would be 1.
First I'm going to recommend you make better choices in naming your variables. You do this:
bool cont = false;
string str;
int num, num2;
cin >> str >> num;
What are num and num2? Give them better names. Why are you cin >> str? I can't even see how you're using it later. But I presume that num is the number of digits you want.
It's also not at all clear what you're using a and b for. Now, I presume this next bit of code is an attempt to create a number. If you're going to blindly try and then when done, see if it's okay, why are you making this so complicated. Instead of this:
num2 = rand() % (a - b) + b;
int r;
int i = 0;
int cpy = num2;
while (cpy != 0) {
r = cpy % 10;
arr[i] = r;
i++;
cpy = cpy / 10;
}
You can do this:
for(int index = 0; index < numberOfDesiredDigits; ++index) {
arr[index] = rand() % 10;
}
I'm not sure why you went for so much more complicated.
I think this is your code where you validate:
// So you iterate the entire array
for (int m = 0; m < num; m++)
{
// And then you check all the values less than the current spot.
for (int j = 0; j < m; j++) {
// This if not needed as j is always less than m.
if (m != j) {
// This if-else is flawed
if (arr[m] == arr[j]) {
break;
}
else {
cont = true;
}
}
}
}
You're trying to make sure you have no duplicates. You're setting cont == true if the first and second digit are different, and you're breaking as soon as you find a dup. I think you need to rethink that.
bool areAllUnique = true;
for (int m = 1; allAreUnique && m < num; m++) {
for (int j = 0; allAreUnique && j < m; ++j) {
allAreUnique = arr[m] != arr[j];
}
}
As soon as we encounter a duplicate, allAreUnique becomes false and we break out of both for-loops.
Then you can check it.
Note that I also start the first loop at 1 instead of 0. There's no reason to start the outer loop at 0, because then the inner loop becomes a no-op.
A better way is to keep a set of valid digits -- initialized with 1 to 10. Then grab a random number within the size of the set and grabbing the n'th digit from the set and remove it from the set. You'll get a valid result the first time.

C++ Largest number in array. Positive and negative

I have a task to print maximum int of matrix second line.
Example input:
3 2 (n, m)
-1 -2 <- 1 line
4 5 <- 2 line
2 6 <- 3 line
Max int in second line is 5. My program prints it. But if second line would be -100 -150, it not works. Sure it is because I have max = 0, but I don't know how to use it properly. I'm a student. Thanks in advance.
It is my code:
#include <iostream>
using namespace std;
int main() {
int n, m, max = 0;
cin >> n >> m;
int matrix[10][10];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> matrix[i][j];
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (matrix[1][j] > max) {
max = matrix[1][j];
}
}
}
if (max == 0 || n == 1) {
cout << "No";
} else {
cout << max;
}
}
And code works pretty good, unless there are negative numbers in second line
You are correct to suspect max = 0;. Why is that a problem? Well, first, perhaps you should try to explain to your rubber duck why it is correct. As you try to do so, you are likely to express an intent along the lines of "this value will not make it through the checks" or "this value will be replaced in the first iteration of the loop". Why? "Because matrix[1][j] > max will be true, so... Hold on, wasn't the problem when matrix[1][j] > 0 is false? So when max is 0, um... problem?"
The overall strategy is valid, but there is a requirement that max be initialized to a low enough value. There are two common strategies I can think of at the moment.
Use a value that is as low as possible for the type you are using. That is:
int max = std::numeric_limits<int>::lowest();
Use the value from the first iteration of the loop. No need to provide a value that is just going to be replaced anyway. There are some caveats for this, though. The most relevant for your example can be expressed as a question: what if there is no first iteration? (Perhaps there is only one row? Perhaps there are no columns?) Also, you would need to initialize max between your loops, after the matrix has been given values.
int max = (n > 1 && m > 0) ? matrix[1][0] : /* what value do you want here? */;

Find the number of pairs of positive integers satisfying the inequality

I'm trying to solve a programming problem where I have to display the number of positive integer solutions of the inequality x² + y² < n, where n is given by the user. I've already written a code that seems to work but not as fast as I'd like it to. Is there any way to speed it up?
My current code:
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
long long n, i, r, k, p, a;
cin >> k;
while (k--)
{
r = 0;
cin >> n;
p = sqrt(n);
for (i = 1; i <= p; i++)
{
a = sqrt(n - (i * i));
r += a;
if ((((i * i) + (a * a)) == n) && (a > 0))
{
r--;
}
}
cout << r << "\n";
}
return 0;
}
Edit:
This is a solution for this task.
The task in English:
Find the number of natural solutions (x≥1, y≥1) of the inequality x²+y² < n, where 0 < n < 2147483647. For example, for n=10 there are 4 solutions: (1,1), (1,2), (2,1), (2,2).
Input
In the first line of input the number of test cases k is given. In the next k lines, there are the n values given.
Output
In the output, you have to display in separate lines the number of natural solutions of the inequality.
Example
Input:
2
10
11
Output:
4
6
Your solution seems fast already. The main possibility to reduce the time spent is to suppress the call to sqrtin the loop. This is obtained by considering that the value a = sqrt(n - (i * i)) does not vary very much from one iteration to the next one.
Here is the code:
r = 0;
p = sqrt(n);
if ((p*p) == n) p--;
a = p;
for (long long i = 1; i <= p; i++)
{
while ((n-i*i) <= a*a) {
--a;
}
r += a;
}

Find the amount of changes in the sign of number in an array

Basically, I have an array given of "x" numbers and I have to output the amount of how many times the sign changed in the numbers of the array.
For example array is:
2 -4 5 6 7 -2 5 -7
The output should be 5. Why? Because the sign changes first time at -4, second time at 5, third time at -2, fourth time at 5 and last time at -7. Total 5 times.
So, I have this so far but that doesn't work perfectly:
#include <iostream>
using namespace std;
int main()
{
int a[50],n,cs=0,ha=0;
cin >> n;
for (int i=0;i<n;i++)
{
cin >> a[i];
}
for (int j=1;j<=n;j++)
{
if(a[j]<0 && a[j-1]>0)
cs++;
else if(a[j]>0 && a[j-1]<0)
cs++;
}
cout << cs << endl;
return 0;
}
Please help!
Your problem is that you're running into uninitialized memory, which is causing undefined behaviour. You initialize a[0] through a[n-1] in your input loop and then read from a[0] (with j=1 and a[j-1]) to a[n] (j=n and a[j]) in your calculation loop.
Simply change it to j < n.
If STL is an option for you, you can use std::adjacent_find. This is how you would use it in a complete program:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
vector<int> v { 1 , 3, -5, 8, -9, -10, 4 };
auto signSwitch = [] (int x, int y) { return (abs(x) == x) ^ (abs(y) == y); };
int cnt = 0;
auto i = adjacent_find(begin(v), end(v), signSwitch);
while (i != end(v))
{
cnt++;
i = adjacent_find(i + 1, end(v), signSwitch);
}
cout << cnt;
}
Your second loop should terminate at j < n.
On your second for loop you should not have j go to <=. it should just be
for (int j=1;j<n;j++)