Skip to main content
added 37 characters in body
Source Link
LambdaBeta
  • 2.8k
  • 13
  • 20

C (gcc), 128128 125 bytes

p(_){printf("%d ",_);}f(n,x,y,i){x=n*n;y=1;for(i=0;++i<n;i=0;++i<n;p(y){,x-=y++)while(rand()&&(n-i)*(n-i+1)/2+(n-i)*(y+1)+y<x)y++;p(y);x-=y++;}p(x);} 

Try it online!Try it online!

-3 bytes thanks to ceilingcat

C (gcc), 128 bytes

p(_){printf("%d ",_);}f(n,x,y,i){x=n*n;y=1;for(i=0;++i<n;){while(rand()&&(n-i)*(n-i+1)/2+(n-i)*(y+1)+y<x)y++;p(y);x-=y++;}p(x);} 

Try it online!

C (gcc), 128 125 bytes

p(_){printf("%d ",_);}f(n,x,y,i){x=n*n;y=1;for(i=0;++i<n;p(y),x-=y++)while(rand()&&(n-i)*(n-i+1)/2+(n-i)*(y+1)+y<x)y++;p(x);} 

Try it online!

-3 bytes thanks to ceilingcat

Source Link
LambdaBeta
  • 2.8k
  • 13
  • 20

C (gcc), 128 bytes

p(_){printf("%d ",_);}f(n,x,y,i){x=n*n;y=1;for(i=0;++i<n;){while(rand()&&(n-i)*(n-i+1)/2+(n-i)*(y+1)+y<x)y++;p(y);x-=y++;}p(x);} 

Try it online!

NOTE: The probability is very very far from uniform. See explanation for what I mean and a better means to test that it works (by making the distribution closer to uniform [but still a far cry from it]).

How?

The basic idea is to only choose increasing numbers so as to not worry about duplicates. Whenever we pick a number we have a non-zero chance of 'skipping' it if allowable.

To decide if we can skip a number we need to know x the total left to be reached, k the number of elements we still have to use, and y the current candidate value. The smallest possible number that we could still pick would consist of $$y+(y+1)+(y+2)+...$$ added to the current value. In particular we require the above expression to be less than x. The formula will be $$\frac{k(k+1)}{2}+k(y+1)+y<x$$ Unfortunately we have to be a bit careful about rearranging this formula due to integer truncation in C, so I couldn't really find a way to golf it.

Nonetheless the logic is to have a chance to discard any y that satisfies the above equation.

The code

p(_){printf("%d ",_);} // Define print(int) f(n,x,y,i){ // Define f(n,...) as the function we want x=n*n; // Set x to n^2 y=1; // Set y to 1 for(i=0;++i<n;){ // n-1 times do... while(rand()&& // While rand() is non-zero [very very likely] AND (n-i)* // (n-i) is the 'k' in the formula (n-i+1)/2+ // This first half takes care of the increment (n-i)*(y+1) // This second half takes care of the y+1 starting point +y<x) // The +y takes care of the current value of y y++; // If rand() returned non-zero and we can skip y, do so p(y); // Print y x-=y++; // Subtract y from the total and increment it }p(x);} // Print what's left over. 

The trick I mentioned to better test the code involves replacing rand()&& with rand()%2&& so that there is a 50-50 chance that any given y is skipped, rather than a 1 in RAND_MAX chance that any given y is used.