The "problem" with wanting to ask too much in a single question (and I can know, I have the same problem when submitting questions) is that readers can get at the correct answer by knowing just a subset. In my case, I knew what the result of all except the last two (with "ALL") would be. Turns out I actually needed to know only the first two to be left with only one answer that had to be correct.
The behaviour of COUNT is actually not that interesting at all. COUNT(expression) counts the number of rows for which the expression is not NULL. So COUNT(constant) is the same as COUNT(*) or COUNT(non-nullable column), and presents the number of rows. I personally have a great dislike for COUNT(constant) and/or COUNT(non-nullable column), as I think that COUNT(*) much better communicates to the future maintaiiner of the query that we are counting rows.
COUNT(NULL) would return 0 but it is actually invalid, but COUNT(CAST(NULL as int)) does indeed return 0. This for trivia purpose only, I really hope nobody ever uses this.
COUNT(nullable column) is in some cases needed, if we need to find the number of non-NULL values. Or COUNT(*) - COUNT(nullable column) will return the number of NULL values in the column.
Adding DISTINCT does exactly what it says on the package: it removes duplicates before counting. COUNT(DISTINCT constant) would return 0 for an empty table and 1 in all other cases, and is therefor just as useless as COUNT(NULL). COUNT(DISTINCT column) is a perfect way to find out how many different values there are in a column. Beware that this may be expensive on a non-indexed column, because SQL Server has to either sort the data or use a hash table to detect and remove duplicates - and those are expensive operators in the execution plan.