Here's the formulation of the linear program and the Gurobi code to solve it:

**Decision Variables:**

* `x1`: Number of billboard ads
* `x2`: Number of podcast ads
* `x3`: Number of merchandise ads

**Objective Function:**

Maximize total viewership: `40000x1 + 10000x2 + 2000x3`

**Constraints:**

* **Budget Constraint:** `750x1 + 1000x2 + 300x3 <= 20000`
* **Billboard Limit:** `x1 <= 3`
* **Merchandise Proportion:** `x3 <= 0.4 * (x1 + x2 + x3)`
* **Podcast Proportion:** `x2 >= 0.25 * (x1 + x2 + x3)`
* **Non-negativity:** `x1, x2, x3 >= 0`
* **Integer Constraint:** `x1, x2, x3` are integers


```python
import gurobipy as gp

# Create a new model
model = gp.Model("Maximus_Advertising")

# Create variables
x1 = model.addVar(vtype=gp.GRB.INTEGER, name="billboard_ads")
x2 = model.addVar(vtype=gp.GRB.INTEGER, name="podcast_ads")
x3 = model.addVar(vtype=gp.GRB.INTEGER, name="merchandise_ads")

# Set objective function
model.setObjective(40000*x1 + 10000*x2 + 2000*x3, gp.GRB.MAXIMIZE)

# Add constraints
model.addConstr(750*x1 + 1000*x2 + 300*x3 <= 20000, "budget_constraint")
model.addConstr(x1 <= 3, "billboard_limit")
model.addConstr(x3 <= 0.4*(x1 + x2 + x3), "merchandise_proportion")
model.addConstr(x2 >= 0.25*(x1 + x2 + x3), "podcast_proportion")

# Optimize model
model.optimize()

# Print results
if model.status == gp.GRB.OPTIMAL:
    print(f"Optimal Viewership: {model.objVal}")
    print(f"Number of Billboard Ads: {x1.x}")
    print(f"Number of Podcast Ads: {x2.x}")
    print(f"Number of Merchandise Ads: {x3.x}")
elif model.status == gp.GRB.INFEASIBLE:
    print("The model is infeasible.")
else:
    print(f"Optimization ended with status {model.status}")

```
