## Problem Description and Formulation

Nolan needs to maximize his score in a contest with multiple choice questions worth 2 points each and short answer questions worth 5 points each. The constraints are:

- He can answer at most 30 questions in total.
- He must answer at least 15 multiple choice questions.
- He must answer at least 10 short answer questions.
- He can answer at most 20 multiple choice questions.
- He can answer at most 20 short answer questions.

Let's denote:
- \(x\) as the number of multiple choice questions Nolan answers.
- \(y\) as the number of short answer questions Nolan answers.

The objective is to maximize the total score: \(2x + 5y\).

The constraints can be formulated as:
1. \(x + y \leq 30\)
2. \(x \geq 15\)
3. \(y \geq 10\)
4. \(x \leq 20\)
5. \(y \leq 20\)
6. \(x, y \geq 0\) and are integers (though Gurobi can handle continuous variables, we'll ensure integrality is considered in the solution process).

## Gurobi Code

```python
import gurobi

def nolan_contest():
    # Create a new model
    model = gurobi.Model()

    # Define variables
    x = model.addVar(lb=0, ub=20, name="multiple_choice")
    y = model.addVar(lb=0, ub=20, name="short_answer")

    # Objective function: maximize 2x + 5y
    model.setObjective(2*x + 5*y, gurobi.GRB.MAXIMIZE)

    # Constraints
    model.addConstr(x + y <= 30, name="total_questions")
    model.addConstr(x >= 15, name="min_multiple_choice")
    model.addConstr(y >= 10, name="min_short_answer")
    model.addConstr(x <= 20, name="max_multiple_choice")
    model.addConstr(y <= 20, name="max_short_answer")

    # Integrate and solve
    model.optimize()

    # Print solution
    if model.status == gurobi.GRB.OPTIMAL:
        print(f"Objective: {model.objVal}")
        print(f"Multiple choice questions: {x.varValue}")
        print(f"Short answer questions: {y.varValue}")
    else:
        print("No optimal solution found.")

if __name__ == "__main__":
    nolan_contest()
```