This looks good. Don't worry about being "rough on the database"
With this design, You will need to get hundreds of thousands of rows before you see a noticeable performance hit (like > 1 second).
You definitely want the zip codes on the Reporting table. In a normal design it would be attached to the agency, but for reporting, you need historical accuracy. This prevents problems when an agency adds or drops a zip code.
You could have the current zip codes tied to the agency, and copy them to the monthly report via trigger or manually.
I don't see any other issues here.