#include <stdio.h>
#include <stdlib.h>

#include <iostream>
#include <iomanip>
#include <sstream>
#include <stdint.h>
#include <string.h>

#include <unordered_set>

#define _USE_MATH_DEFINES
#include <math.h>


#include <vector>
#include <list>

#include <set>
#include <map>

#include <unordered_map>

#include <queue>

#include <string>

#include <vector>

#define sqr(x) (x) * (x)

#include <algorithm>
#include <functional>

#include <bitset>

#include <functional>

#include <chrono>

typedef unsigned int u32;
typedef int i32;

typedef unsigned long long int u64;
typedef long long int i64;

typedef uint16_t u16;
typedef int16_t i16;

typedef uint8_t u8;
typedef int8_t i8;


using namespace std;
using namespace std::chrono;

struct less_key
{
    bool operator() (pair<i64, i64> p1, pair<i64, i64> p2)
    {
        return p1.first < p2.first || (p1.first == p2.first && p1.second < p2.second);
    }
};

struct less_key2
{
    bool operator() (pair<i64, i64> p1, pair<i64, i64> p2)
    {
        return p1.second > p2.second || (p1.second == p2.second && p1.first > p2.first);
    }
};

//
//struct pair_hash
//{
//    std::size_t operator()(const i64& k) const
//    {
//        return static_cast<size_t>(k.first ^ k.second);
//    }
//};

#include <random>

const i64 mod = 1000000007ll;
const i64 mod2 = 998244353ll;
const i64 inf = 10000000000000007ll;

const double eps = 1e-10;

template <typename T = i64, T D = 0>
class MaxOp {
public:
    static T op(const T& a, const T&b) {
        return max(a, b);
    }

    static T def() {
        return (T)D;
    }
};

template <typename T = i64, T D = inf>
class MinOp {
public:
    static T op(const T& a, const T&b) {
        return min(a, b);
    }

    static T def() {
        return (T)D;
    }
};

template <typename T = i64, T D = 0>
class SumOp {
public:
    static T op(const T& a, const T&b) {
        return a + b;
    }

    static T def() {
        return (T)D;
    }
};

template <typename D, typename T = i64>
class SegTree {
public:
    i64 n;
    vector<T> t;

private:
    void build(const i64* a, int v, int tl, int tr) {
        if (tl == tr)
            t[v] = a[tl];
        else {
            int tm = (tl + tr) / 2;
            build(a, v * 2, tl, tm);
            build(a, v * 2 + 1, tm + 1, tr);
            t[v] = D().op(t[v * 2], t[v * 2 + 1]);
        }
    }

    i64 get(int v, int tl, int tr, int l, int r) {
        if (l > r) {
            return D().def();
        }
        if (l == tl && r == tr) {
            return t[v];
        }
        int tm = (tl + tr) / 2;
        return D().op(get(v * 2, tl, tm, l, min(r, tm)),
            get(v * 2 + 1, tm + 1, tr, max(l, tm + 1), r));
    }

    void update(int v, int tl, int tr, int pos, int new_val) {
        if (tl == tr) {
            t[v] = new_val;
        }
        else {
            int tm = (tl + tr) / 2;
            if (pos <= tm) {
                update(v * 2, tl, tm, pos, new_val);
            }
            else {
                update(v * 2 + 1, tm + 1, tr, pos, new_val);
            }
            t[v] = D().op(t[v * 2] + t[v * 2 + 1]);
        }
    }

public:
    void build(const vector<i64 >& a) {
        n = a.size();
        t.resize(n * 4);
        build(a.data(), 1, 0, n - 1);
    }

    void build(i64* a, i64 n) {
        this->n = n;
        t.resize(n * 4);
        build(a, 1, 0, n - 1);
    }

    i64 get(i64 l, i64 r) {
        return get(1, 0, n - 1, l, r);
    }

    void update(i64 pos, i64 new_val) {
        update(1, 0, n - 1, pos, new_val);
    }
};

// dsu

i64 parent[100005];

void make_set(i64 v) {
    parent[v] = v;
}

i64 find_set(i64 v) {
    if (v == parent[v])
        return v;
    return parent[v] = find_set(parent[v]);
}

void union_sets(i64 a, i64 b) {
    a = find_set(a);
    b = find_set(b);
    if (a != b)
        parent[b] = a;
}

// del

set<string> e[1020];

inline string norm(string s) {
    string r = s;
    reverse(r.begin(), r.end());
    return s < r ? s : r;
}

inline void ins(map<string, i64>& R, i64 f, const string& s, i64 c) {

    i64 z = 0;
    for (i64 tt = 0; tt < s.size(); tt++) {
        z += s[tt];
    }
    if (f - c != z) {
        throw 1;
    }

    string ns = norm(s);
    e[f - c].insert(ns);
    R.insert({ ns, c });
}

void next(const string& q, map<string, i64>& R, i64 ff) {
    if (q.size() > 0) {
        ins(R, ff, q.substr(1), q[0]);
        ins(R, ff, q.substr(0, q.size() - 1), q[q.size() - 1]);

        for (i64 i = 1; i < q[0]; i++) {
            string t = q;
            t[0] -= i;
            ins(R, ff, t, i);
        }

        for (i64 i = 1; i < q[q.size() - 1]; i++) {
            string t = q;
            t[q.size() - 1] -= i;
            ins(R, ff, t, i);
        }
    }

    for (i64 i = 1; i < q.size() - 1; i++) {
        for (i64 j = 1; j < q[i]; j++) {
            string t = q;
            t[i] -= j;
            ins(R, ff, t, j);
        }


        string f = "#";
        f[0] = q[i - 1] + q[i + 1];
        //cerr << "i = " << i << "; " << q.substr(0, i - 1) + "+" << f << "+" << q.substr(i + 2) << endl;
        string t = q.substr(0, i - 1) + f + q.substr(i + 2);
        ins(R, ff, t, q[i]);
    }
}

int main() {
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cout.precision(15); cout.setf(ios::fixed);


    i64 n, a, b;
    cin >> n >> a >> b;

    cout << min(a, b) << " " << max(0ll, a + b - n);

    return 0;
}

Measured memory_bytes: 256