What's the best way to build URLs for dynamic content collections?
You need that custom route. With the dynamic URI setting the "entry route" is generated dynamically on entry save, but it stores a single, fixed route only.

But you don't have to miss out on Live Preview when you leave the "entry route" enabled in addition to your custom route. Set up separate Live Preview URIs that you don't link to and if you prefer you can 404 the request for all non Live Preview visits.

{% if not craft.request.isLivePreview %}
    {% exit 404 %}
{% endif %}