You can either use the array syntax or a typedef-name to allocate arrays with new - both is allowed and equivalent according to [expr.new]/5:
When the allocated object is an array (that is, the
noptr-new-declarator syntax is used or the new-type-id or type-id
denotes an array type), the new-expression yields a pointer to the
initial element (if any) of the array.
As you can see, for arrays, solely a pointer to the initial element is given; Not a pointer to the array object itself. Thus the type yielded is int*, not int (*)[N].
The reason why a pointer to the initial element is returned is quite simple: It is the pointer that you want to work with.
We want to write
auto p = new int[50];
// Or
int* p = new int[50];
So as to be able to use normal subscripting:
p[49] = 0xDEADBEEF;
That would be nonsensical with p if it was of type int(*)[50] pointing to the array object, because the subscript would add 49*50*4 to the address, not just 49*4 - because of subscript semantics and pointer arithmetics.
We would have to either use two subscripts:
p[0][49] = ...;
Which is horrific and unnecessarily redundant. Or we could use a cast:
int* p = static_cast<int*>(new int[50]); // Or with auto
But that is ugly too.
To avoid such hassles, this rule was introduced.
arraycontainer class for fixed size collections.