use List::Util 'min'; use POSIX 'ceil'; sub num_ways { my ($N, $S, $T) = @_; return 1 if $S == 0 and $T == 0; return 0 if $N < 1 or $S < 1 or $T < 1; my $min = (2*$T-$S+$S**2)/(2*$S); ## more correctly, ceil() of this my $max = min( $T-(($S-1)*$S/2), $N ); my $sum = 0; for my $K ($min .. $max) { $sum += num_ways( $K-1, $S-1, $T-$K ); } return $sum; } use Memoize; memoize 'num_ways'; print num_ways(100, 10, 667), $/;