Question: http://codeforces.com/contest/468/problem/B
Little X has n distinct integers: p1, p2, ..., pn. He wants to divide all of them into two sets A and B. The following two conditions must be satisfied:
If number x belongs to set A, then number a - x must also belong to set A.
If number x belongs to set B, then number b - x must also belong to set B.
Help Little X divide the numbers into two sets or determine that it's impossible.
Input
The first line contains three space-separated integers n, a, b (1 ≤ n ≤ 105; 1 ≤ a, b ≤ 109). The next line contains n space-separated distinct integers p1, p2, ..., pn (1 ≤ pi ≤ 109).
Output
If there is a way to divide the numbers into two sets, then print "YES" in the first line. Then print n integers: b1, b2, ..., bn (bi equals either 0, or 1), describing the division. If bi equals to 0, then pi belongs to set A, otherwise it belongs to set B.
If it's impossible, print "NO" (without the quotes).
Now, I developed the following code:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
using namespace std;
int n,a,b,id;
int p[100100];
set<int> st;
map<int,int> mp;
int fa[100100];
int find(int x)
{
if(x==fa[x]) return x;
return fa[x]=find(fa[x]);
}
void Bing(int a,int b)
{
int A=find(a),B=find(b);
if(A==B) return ;
fa[B]=A;
}
int main()
{
scanf("%d%d%d",&n,&a,&b);
for(int i=1;i<=n;i++)
{
scanf("%d",p+i);
st.insert(p[i]);
mp[p[i]]=++id;
fa[i]=i;
}
fa[n+1]=n+1;///A
fa[n+2]=n+2;///B
for(int i=1;i<=n;i++)
{
int x=p[i];
int flag = 0;
if(st.count(a-x))
{
Bing(mp[x],mp[a-x]);
flag = 1;
}
else
{
Bing(n+1,mp[x]);
flag = 1;
}
if(st.count(b-x) && flag == 0)
{
Bing(mp[x],mp[b-x]);
}
else if (flag == 0)
{
Bing(n+2,mp[x]);
}
}
if(find(n+1)==find(n+2))
{
puts("NO");
}
else
{
puts("YES");
for(int i=1;i<=n;i++)
{
printf("%d ",find(i)==find(n+1));
}
putchar(10);
}
return 0;
}
Basically, try to merge every element with either in Set A or in Set B. And then finally output NO if both of them are merged in turn. However, this gives a wrong answer on input as:
3 3 4
1 2 4
Output should be: NO whereas my code gives output as
YES
0 0 1
Where am I going wrong in my logic? Please help!
Consider the following cases for P being the set of all input numbers p[i]:
There is a number n1 in P that satisfies n1 = a - p[i] but no number n2 in P that satisfies n2 = b - p[i]
There is a number n1 in P that satisfies n1 = b - p[i] but no number n2 in P that satisfies n2 = a - p[i]
There is no number n in P that satisfies n = a - p[i] OR n = b - p[i]
There is a number n1 in P that satisfies n1 = a - p[i] AND a number n2 in P that satisfies n2 = b - p[i]
Whatever else may happen, if you run into situation 3. or 4. you want to report a failure ("NO").
If all numbers p[i] belong to case 1. or 2. the result should be valid.
You should check your code line by line, if it is compatible with the provided cases here.
Related
this function prints all triplets in an array whose product is a number k
input first line number of elements, second array elements, third target product .. passes parameters to recursive function f along with a vector that stores elements whose product might give k
thought process -> for each element we can include or exclude it to get the product k. If p > 24 or number elements multiplied > 3 we backtrack. once the prod = k, we print all numbers from vector v and pop them out and set number of elements count to 0 and product to 1 and continue
for an input of:
9
1 2 3 12 4 7 5 24 9
24
my output looks something like this :
12
2
1
9
9
9
| ->cursor justs stops here ..no further outputs...
naming scheme used :
count -> number of elements multiplied till now whose product is stored in -> p
n-> number of elements in array
k -> target pdt
i -> index of element in array currently at
code :
#include <iostream>
#include <vector>
using namespace std;
// all triplets whose product is a number k
void f(int i, int count, int p, int k, vector<int>&v, int *a, int n)
{
// success condition
if(count == 3 && p == k)
{
for(int i = 2; i >= 0; --i)
{
cout << v[i] << " " << endl;
v.pop_back();
}
p = 1;
count = 0;
}
if(count>=3 || i > n - 1 || p > k)
{
return;
}
v.push_back(a[i]);
f(i + 1, count + 1, p * a[i], k, v, a, n);
v.pop_back();
f(i + 1, count, p, k, v, a, n);
}
int main()
{
int n;
cin >> n;
int *a=new int[n];
for(int i = 0; i < n; ++i)
{
cin >> a[i];
}
int k;
cin >> k;
//int p = 1;
vector<int>v;
f(0, 0, 1, k, v, a, n);
delete[] a;
return 0;
}
Your “reset” of p and count on success is immediately strange: why does the function need to keep looking when its caller will already try the other possibilities? But that’s just a distraction from the real issue: the balanced push_back and pop_back around the first recursive call establish and rely on an invariant where every call leaves v the same length as when it started. But the success path clears the vector and leaves it shorter, so eventually you pop_back when it’s empty and—
The joys of undefined behavior (which happened to give an infinite loop here) aside, the fix is trivial: just return after printing without modifying v at all. (Then you may find some further simplifications.)
I have this problem from hackerearth
Given an array of N integers, C cards and S sum. Each card can be used
either to increment or decrement an integer in the given array by 1.
Find if there is any subset (after/before using any no.of cards) with
sum S in the given array.
Input Format
First line of input contains an integer T which denotes the no. of
testcases. Each test case has 2 lines of input. First line of each
test case has three integers N(size of the array), S(subset sum) and
C(no. of cards). Second line of each test case has N integers of the
array(a1 to aN) seperated by a space.
Constraints
1<=T<=100 1<=N<=100 1<=S<=10000 0<=C<=100 1<=ai<=100
Output Format
Print TRUE if there exists a subset with given sum else print FALSE.
So this is basically a variation of the subset sum problem, but instead of finding out whether a given subset with a sum S exists, we need to find the largest subset from sequence index to N-1 that has a value of s and compare it's length with our C value to see if it is greater. If it is, then we have enough elements to modify the sum using our C cards, and then we print out our answer. Here is my code for that
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int N, S, C;
int checkSum(int index, int s, vector<int>& a, vector< vector<int> >& dP) {
if (dP[index][s] != -1)
return dP[index][s];
int maxNums = 0; // size of maximum subset array
for (int i = index; i < N; i++) {
int newSum = s - a[i];
int l = 0;
if (newSum == 0) {
l = 1;
} if (newSum > 0) {
if (i < (N-1)) { // only if we can still fill up sum
l = checkSum(i + 1, newSum, a, dP);
if (l > 0) // if it is possible to create this sum
l++; // include l in it
} else {
// l stays at 0 for there is no subset that can create this sum
}
} else {
// there is no way to create this sum, including this number, so skip it;
if (i == (N-1))
break; // don't go to the next level
// and l stays at 0
}
if (l > maxNums) {
maxNums = l;
}
}
dP[index][s] = maxNums;
return maxNums;
}
int main() {
int t;
cin >> t;
while (t--) {
cin >> N >> S >> C;
vector<int> a(N);
for (int i = 0; i < N; i++)
cin >> a[i];
vector< vector<int> > dP(N, vector<int>(S + C + 2, -1));
bool possible = false;
for (int i = 0; i <= C; i++) {
int l = checkSum(0, S-i, a, dP);
int m = checkSum(0, S+i, a, dP);
if ( (l > 0 && l >= i) || (m > 0 && m >= i) ) {
cout << "TRUE" << endl;
possible = true;
break;
}
}
if (!possible)
cout << "FALSE" << endl;
}
return 0;
}
So basically, 0 means it's not possible to create a subset equal to s from elements index to N-1, and -1 means we haven't computed it yet. And any other value indicates the size of the largest subset that sums up to s. This code isn't passing all the test cases. What's wrong?
You miss an else in following line
} if (newSum > 0) {
This make your program has an unexpected early break before updating maxNums by l in some cases.
For example, N=1, S=5, C=0, a={5}
Potential logic problem
You have limited the no. of card to be used to not exceed the subset size while the question never state you cannot apply multiple cards to same integers.
I mean l >= i and m >= i in
if ( (l > 0 && l >= i) || (m > 0 && m >= i) ) {
Seems you have logic flaw.
You need to find the shortest subset (with sum in range S-C..S+C) and compare it's size with C. If subset is shorter, it is possible to make needed sum.
I tried to write a program that receive from the user 5 integers and print the second minimum number.
Here is a sample of what I've tried:
#include <iostream>
using namespace std;
int main () {
int a,b,c,d,e;
cin>>a>>b>>c>>d>>e;
if (a>b && a<c && a<d && a<e)
cout<<a<<endl;
if (b>a && b<c && b<d && b<e)
cout<<b<<endl;
if (c>a && c<b && c<d && c<e)
cout<<c<<endl;
if (d>a && d<b && d<c && d<e)
cout <<d<<endl;
if (e>a && e<b && e<c && e<d)
cout <<e<<endl;
return 0;
}
When I enter 1 2 3 4 5 it prints the second minimum, but when I enter
5 4 3 2 1 Nothing will print on the screen. What am I doing wrong with this? Is there any other way to write my program?
The problem you have with your logic is that you do not enforce yourself to print only 1 item, and at least one item.
By using the 'else' part of the if/else syntax, you will ensure that only one branch can ever be hit. You can then follow this up with just an else at the end, as you know all other conditions are false.
Once you've done this, you'll see that you print the last value, (1) rather than the expected (4). This is because your logic regarding how to find the 2nd lowest is wrong. b>a is false for the case 5,4...
Note:
Every employed engineer, ever, would make this a loop in a std::vector / std::array, and I would suggest you point your teacher to this post because encouraging loops is a good thing rather than bad.
Something like
vector<int> data;
for (int i=0; i<5; ++i) {
int t;
cin >> t;
data.push_back(t);
}
std::nth_element(data.begin(), data.begin()+1, data.end(), std::greater<int>());
cout << data[1];
There are 120 possible permutations on 5 elements. Your code should output the correct number for all of them. So a fool-proof code would use 120 repetitions of a check, like the following:
if (a > b && b > c && c > d && d > e) // the order is a>b>c>d>e
cout << d;
else if (a > b && b > c && c > e && e > d) // the order is a>b>c>e>d
cout << e;
...
else if (e > d && d > c && c > a && e > b) // the order is e>d>c>a>b
cout << a;
else // the order is e>d>c>b>a
cout << b;
This is very long, inefficient and tricky code. If you do a typo in just one variable, it will output a wrong answer in some rare cases. Also, it doesn't handle the possibility of some inputs being equal.
If the number of inputs to a sorting algorithm is a known small constant, you can use an approach called sorting networks. This is a well-defined computer science problem, which has well-known optimal solutions for small numbers of inputs, and 5 certainly is small. An optimal sorting network for 5 inputs contains 9 comparators, and is described e.g. here.
Since you don't need to sort the numbers, but only to know the second smallest input, you can reduce the size of the network further, to 7 comparators.
The full sorting network (without the reduction from 9 to 7) translated to C++:
if (b < c)
swap(b, c);
if (d < e)
swap(d, e);
if (b < d)
swap(b, d);
if (a < c)
swap(a, c);
if (c < e)
swap(c, e);
if (a < d)
swap(a, d);
if (a < b)
swap(a, b);
if (c < d)
swap(c, d);
if (b < c)
swap(b, c);
// now the order is a ≥ b ≥ c ≥ d ≥ e
cout << d;
This code is also obscure - not obvious at all how and why it works - but at least it is small and in a sense optimal. Also, it's clear that it always prints something (so it fixes the original problem) and supports the case of partially equal inputs.
If you ever use such code in a larger project, you should document where you took it from, and test it. Fortunately, there are exactly 120 different possibilities (or 32, if you use the
zero-one principle), so there is a way to prove that this code has no bugs.
This should work for you. (Note that it might not be the best approach and you can minimize it with a function to calculate min and secondMin instead of the ugly copy paste of the logic but it will get you started:
#include <iostream>
using namespace std;
int main () {
int a,b,c,d,e;
int min, secondMin;
cin>>a>>b;
min = a < b ? a : b;
secondMin = a < b ? b : a;
cin>>c;
if (c < min)
{
secondMin = min;
min = c;
}
else if (c < secondMin)
{
secondMin = c;
}
cin>>d;
if (d < min)
{
secondMin = min;
min = d;
}
else if (c < secondMin)
{
secondMin = d;
}
cin>>e;
if (e < min)
{
secondMin = min;
min = e;
}
else if (e < secondMin)
{
secondMin = e;
}
cout << "min = " << min << ", secondMin = " << secondMin << endl;
return 0;
}
if you have any questions feel free to ask in the comment
#include <set>
std::set<int> values = { a, b, c, d, e }; // not an array.
int second_min = *std::next(values.begin(), 1); // not a loop
What about a recursive and more generic approach?
No arrays, no loops and not limited to just 5 integers.
The following function get_2nd_min() keeps track of the two lowest integers read from std::cin a total of count times:
#include <climits>
#include <cstddef>
#include <iostream>
int get_2nd_min(size_t count, int min = INT_MAX, int second_min = INT_MAX)
{
if (!count)
return second_min; // end of recursion
// read next value from cin
int value;
std::cin >> value;
// Does second_min need to be updated?
if (value < second_min) {
// Does min also need to be updated?
if (value < min) {
// new min found
second_min = min; // move the so far min to second_min
min = value; // update the new min
} else {
// value is lower than second_min but higher than min
second_min = value; // new second_min found, update it
}
}
// perform recursion
return get_2nd_min(count - 1, min, second_min);
}
In order to read 5 integers and obtain the 2nd lowest:
int second_min = get_2nd_min(5);
One approach is to first find the minimum number, min and then find the smallest value that isn't min. To do this first find the minimum value:
int min = std::min(a, std::min(b, std::min(c, std::min(d, e))));
Now we need to do the same again, but ignoring min. We can do this using a function called triMin which takes 3 values and discards any value that is the minimum:
int triMin(int currentMin, int left, int right)
{
if(currentMin == left) return right;
if(currentMin == right) return left;
return std::min(left, right);
}
You can now combine them to get the answer:
int a = 5, b = 4, c = 3, d = 2, e = 1;
int min = std::min(a, std::min(b, std::min(c, std::min(d, e))));
int min2 = triMin(min, a, triMin(min, b, triMin(min, c, triMin(min, d, e))));
std::cout << "Second min = " << min2 << std::endl;
This prints 2
This task can be fulfilled using one-pass algorithm. There is no need to use any collections (arrays, sets or anything).
This one-pass algorithm is memory efficient - it does not require storing all elements in collection (and wasting memory) and will work even with large number of elements when other solutions fail with out of memory.
General idea of this algorithm is like this:
take each number in order
you need two variables to store minimum and second minimum numbers from all already seen numbers.
when you get number you need to test it with current minumum to find if it is new minimum number.
if it is store it as minimum, store old minimum in second minimumnumber
otherwise check if it is less than second minimum number.
if it is store it as second minimum number.
now second minimum number contains answer for all already seen numbers.
repeat while there numbers that was not seen.
After investigating all numbers second minimum contain the answer.
Here is implementation with c++17 (link to wandbox):
#include <iostream>
#include <optional>
int main()
{
int a, b, c, d, e;
std::cin >> a >> b >> c >> d >> e;
// you can find second minimal number while going through each number once
auto find_current_answer = [minimum = std::optional<int>{}, next_to_minimum = std::optional<int>{}](int next) mutable {
// when receiving next number
// 1. check if it is new minimum
if (!minimum || minimum > next) {
// move values like this: next_to_minimum <- minimum <- next
next_to_minimum = std::exchange(minimum, next);
}
// 2. else check if it is new next_to_minimum
else if (!next_to_minimum || next_to_minimum > next) {
next_to_minimum = next;
}
// 3. return current answer
return next_to_minimum;
};
// repeat as much as you like
find_current_answer(a);
find_current_answer(b);
find_current_answer(c);
find_current_answer(d);
// store answer that is interesting to you
auto result = find_current_answer(e);
// if it has value - it is the answer
if (result) {
std::cout << "Answer: " << *result << '\n';
}
else {
std::cout << "Not enough numbers!\n";
}
}
Update
In this solution I'm using the min function:
#include <iostream>
using namespace std;
int minDifferentFromFirstMin(int x, int y, int firstMin) {
if(x < y) {
if(x != firstMin) {
return x;
}
else {
return y;
}
}
if(y < x) {
if(y != firstMin) {
return y;
}
else {
return x;
}
}
//if x & y are equals, return one of them
return x;
}
int main () {
int a,b,c,d,e;
int iter11, iter12, iter13;
int iter21, iter22, iter23;
int firstMinimum, secondMinimum;
cin>>a>>b>>c>>d>>e;
//iteration 1: find the first minimum
iter11 = min(a, b);
iter12 = min(c, d);
iter13 = min(iter11, iter12);
firstMinimum = min(iter13, e);
//iteration 2: find the second minimum
iter21 = minDifferentFromFirstMin(a, b, firstMinimum);
iter22 = minDifferentFromFirstMin(c, d, firstMinimum);
iter23 = minDifferentFromFirstMin(iter21, iter22, firstMinimum);
secondMinimum = minDifferentFromFirstMin(iter23, e, firstMinimum);
cout<<secondMinimum<<endl;
}
I have to find the the length of largest increasing sub-sequence of an array such that difference between any two consecutive elements of sub-sequence is 1
For example: {5,4,2,1,6,2,3,4,5}
length of largest consecutive increasing sub-sequence : 5 {1,2,3,4,5}
SO far I have tried this:
#include <iostream>
using namespace std;
int a[1000001];
int m[1000001]={0};
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
m[a[i]]=i;
}
int maxm=0;
for(int i=1;i<=n;i++)
{
if(m[a[i]-1]==0 || m[a[i]]<=m[a[i]-1])
{
int k=a[i];
int prev = m[k];
k++;
int c=1;
while(m[k]>prev)
{
c++;
prev=m[k];
k++;
}
maxm=max(maxm,c);
}
}
cout<<maxm;
return 0;
}
But this is giving wrong answer for cases like{2,2,1,2,3,1,2,3,4,3,5}
Any help would be appreciated.
Let's discuss the algorithm here rather than jumping to the answer/code.
Associate a value with each element. The value with any element X will be how many elements from X-1 till 1 have I seen before I encountered X and add 1 to the value because now we have encountered X also.
So since an element of an array is strictly between 1 <= A[i] <= 106 we are in luck.
We make an array for each of the elements, whether they appear in the array or not. This kind of approach is similar to Hash Table
but since all our elements are integers, we are using an array as a simple hash table where key is the index of the array and value is the hash_table[index] i.e.. the value stores in the index.
Now lets dry run our approach for one of our sample inputs :
5 1 5 6 2 3 8 7 4
Initiall the hash-table looks like this :
hash_table = {0,0,0,0,0,0,0,0,0}; // Not showing indices > 8 because they won't be affected.
Now we encounter 5 :
We look up the value of hash_table[4] and add 1 and put it as the value of 5 i.e. hash_table[5] = hash_table[4] + 1
So hash table looks like this now :
hash_table = {0,0,0,0,0,1,0,0,0};
Then we encounter 1 : we do the same thing :
hash_table = {0,1,0,0,0,1,0,0,0};
Like that after taking in all the numbers hash_table looks like this :
hash_table = {0,1,2,3,4,1,2,3,1}
Our answer is the maximum value of the hash_table, which is 4.
Talk is cheap show me the code :
#include <stdio.h>
#define MAX (int)1e6
int h[MAX];
int main ()
{
int N,i,max=0,temp;
scanf ("%d",&N);
for (i=0;i<N;i++)
{
scanf ("%d",&temp);
h[temp] = h[temp - 1] + 1;
if (h[temp] > max)
max = h[temp];
}
printf ("%d\n",max);
return 0;
}
So what if you can't upvote. You can still accept this answer if you found it useful !
You are thinking a bit too complicated. You just have to iterate through the array once and count the lenght of sequences and remeber the longest one :
int main() {
int size;
int input[100000];
/* ... get your input with size elements ... */
int current = 1;
int biggest = 1;
for (int i=1;i<size;i++) {
if (input[i] == input[i-1] + 1) { current++; }
else {
if (current > biggest) { biggest = current; }
current = 1;
}
}
}
There are N integers {1, 2, ..., N} and K ordered pairs of numbers (A, B); A != B; A, B <= N. No pairs are identical (for example (2, 4) can't be inputed more than once). The same element can appear in many pairs. I have to write a C++ program with an algorithm to find the number of permutations of all N integers, where no B from any pair follows its A. Note that pair (A, B) != (B, A).
Example:
n = 5
k = 4
k1: (2, 3)
k2: (1, 4)
k3: (3, 2)
k4: (2, 4)
This perm. is OK: 4 1 3 5 2
This is not OK: 3 1 4 2 5
Here is my brute force solution, checking recursively every possibility:
#include <iostream>
using namespace std;
int n;
bool conflict[1000][1000];
bool visited[1000];
int result = 0;
int currentlength = 0;
void count(int a) {
visited[a] = true;
currentlength++;
if (currentlength == n) {
result++;
visited[a] = false;
currentlength--;
return;
}
for (int i = 1; i <= n; i++) {
if (!visited[i] && !conflict[a][i]) {
count(i);
}
}
visited[a] = false;
currentlength--;
}
int main()
{
int k;
cin >> n >> k;
for (int i = 0; i < k; i++) {
int a, b;
cin >> a >> b;
conflict[a][b] = 1;
}
for (int i = 1; i <= n; i++) {
count(i);
}
cout << result << endl;
return 0;
}
N and K go up to 1000000 and 100000 respectively, so I need to find a more efficient solution.
You can create a complete graph with all the numbers, and remove the edges corresponding to input pairs.
In the resulting graph, each hamiltonian path corresponds to a solution. So you need an algorithm to find the number of hamiltonian path in a given graph.
Unfortunately there is no time efficient solution. That is, you have to enumerate all possible paths to count them. So, in short, look for algorithms to count hamiltonian paths.
Here are some discussions:
A so thread that discusses this exact problem
wolfram link
Depending on number of input pairs, perhaps it is easier to count the number of solutions that break your conditions. You can subtract it from the total number of possibilities (n!) to get the answer you want.