#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <algorithm>
#include <stack>

using namespace std;

void problemA()
{
    int N;
    vector<int> A, B;

    cin >> N;
    A.reserve(N);
    B.resize(N);

    for (int i = 0; i < N; ++i) {
        cin >> B[i];
    }

    vector<int> inverseOrderOps;

    while (!B.empty()) {
        int maxV = -1, maxIdx = -1;
        for (int bi = int(B.size()) - 1; bi >= 0; bi--) {
            // Is this valid operation?
            if (bi + 1 != B[bi]) continue;

            // Find max value from B
            if (maxV < B[bi]) {
                maxV = B[bi];
                maxIdx = bi;
            }
        }

        if (maxV < 0) {
            cout << "-1" << endl;
            return;
        }

        inverseOrderOps.push_back(maxIdx+1);
        B.erase(B.begin() + maxIdx);
    }

    for (int i = int(inverseOrderOps.size()) - 1; i >= 0; --i) {
        cout << inverseOrderOps[i] << endl;
    }
}


enum Op
{
    Add,
    Remove,
};

struct Vset
{
    int prevUseCount;
    int from, to;
};

bool checkIsGraphValid_S(vector<vector<int>> &Mat, int N, int &maxSum) {

    int firstSum = -1;
    maxSum = 0;
    bool success = true;
    for (int i = 1; i <= N; ++i) {
        int idx = i - 1;

        auto &adjs = Mat[idx];

        int sum = 0;
        bool connectExists = false;
        for (int v = 1; v <= N; ++v) {
            if (v - 1 == idx) continue;
            if (adjs[v - 1] == 0) continue;
            sum += v;
            connectExists = true;
        }

        if (!connectExists) {
            continue;
        }

        maxSum = std::max(maxSum, sum);
        if (firstSum < 0)
        {
            firstSum = sum;
            maxSum = sum;
        }
        else if (sum != firstSum)
        {
            success = false;
        }
    }

    return success;
};

void outputResult (vector<vector<int>> &Mat, int N) {
    vector<pair<int, int>> Vlist;
    for (int p1 = 1; p1 <= N; p1++) {
        for (int p2 = p1 + 1; p2 <= N; p2++) {
            if (Mat[p1 - 1][p2 - 1]) {
                Vlist.emplace_back(p1, p2);
            }
        }
    }
    cout << Vlist.size() << endl;
    for (auto &v : Vlist) {
        cout << v.first << " " << v.second << endl;
    }
};

bool B_graph_recurs(vector<vector<int>> &Mat, int N, bool *pUsed, int from, int to, int curUsedCount)
{
    if (from == to) return false;
    // Add
    auto pFrom = from;
    auto pTo = to;
    if (Mat[pFrom][pTo] == 1) return false;
    if (Mat[pTo][pFrom] == 1) return false;

    if (!pUsed[pTo]) curUsedCount++;
    pUsed[pTo] = true;
    Mat[pFrom][pTo] = 1;
    Mat[pTo][pFrom] = 1;

    if (curUsedCount >= N) {
        int maxSum;
        bool checkRet = checkIsGraphValid_S(Mat, N, maxSum);
        if (!checkRet) {
            if (maxSum > N * 2) {
                // Fail...
                //cout << "--fail--" << endl;
                //outputResult(Mat, N);
                pUsed[pTo] = false;
                Mat[pFrom][pTo] = 0;
                Mat[pTo][pFrom] = 0;
                return false;
            }
        }
        else {
            // Success! Good graph!
            outputResult(Mat, N);
            return true;
        }
    }

    for (int adj = 0; adj < N; adj++) {
        // Next connection

        // Widen direction
        if (B_graph_recurs(Mat, N, pUsed, from, adj, curUsedCount)) {
            return true;
        }

        // Deep directoin
        if (B_graph_recurs(Mat, N, pUsed, to, adj, curUsedCount)) {
            return true;
        }

    }

    pUsed[pTo] = false;
    Mat[pFrom][pTo] = 0;
    Mat[pTo][pFrom] = 0;
    return false;
}

void problemB()
{
    int N;
    cin >> N;

    vector<vector<int>> Mat(N);
    for (int i = 0; i < N; i++) {
        Mat[i] = vector<int>(N);
    }

    bool *pUsed = new bool[N];
    std::fill(pUsed, pUsed + N, false);

    std::stack<pair<Op, Vset>> operations;
    for (int p = 1; p <= N; ++p) {
        pUsed[p - 1] = true;
        for (int p2 = 1; p2 <= N; ++p2) {
            if (p == p2) continue;
            if (B_graph_recurs(Mat, N, pUsed, p-1, p2 - 1, 1)) {
                p = N;
                break;
            }
        }
        pUsed[p - 1] = false;
    }

    delete[] pUsed;
}

void refinedB()
{
    int N;
    cin >> N;

    vector<pair<int, int>> groups;
    int oddFinal = N;
    if (N % 2 == 1) {
        groups.emplace_back(N, -1);
        oddFinal = N - 1;
    }


    for (int i = 1; i <= oddFinal / 2; i++) {
        groups.emplace_back(i, oddFinal - (i - 1));
    }

    auto output = [](int v1, int v2) {
        cout << std::min(v1, v2) << " " << std::max(v1, v2) << endl;
    };

    vector<pair<int, int>> outputPairs;

    for (int i = 0; i < groups.size(); i++) {

        const auto group1 = groups[i];
        for (int j = i+1; j < groups.size(); j++) {
            const auto group2 = groups[j];


            outputPairs.emplace_back(group1.first, group2.first);
            if (group2.second >= 0) {
                outputPairs.emplace_back(group1.first, group2.second);
            }
            if (group1.second >= 0) {
                outputPairs.emplace_back(group1.second, group2.first);
                if (group2.second >= 0) {
                    outputPairs.emplace_back(group1.second, group2.second);
                }
            }
        }
    }

    cout << outputPairs.size() << endl;
    for (int i = 0; i < outputPairs.size(); i++) {
        output(outputPairs[i].first, outputPairs[i].second);
    }

}

int main()
{
    //problemA();
    //problemB();
    refinedB();
}


Measured memory_bytes: 384