import java.util.Scanner;
// 参考百度百科:https://baike.baidu.com/item/%E6%9D%A8%E8%BE%89%E4%B8%89%E8%A7%92/215098
//
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int N = in.nextInt();// 输出杨辉三角形的前n行
// 1.初始化数组
long[][] arr = new long[N][];
for (int i = 0; i < arr.length; i++) {
arr[i] = new long[i + 1];
}
// 2.填充数据
for (int n = 0; n < arr.length; n++) {
for (int k = 0; k < arr[n].length; k++) {
long num = 1;
for (int i = 1; i <= k; i++) {
// 这段代码 num = num * (n - i + 1) / i; 是在计算二项式系数(组合数)的高效算法
// 二项式系数公式,二项式系数 C(n, k) 表示从 n 个元素中取 k 个的组合数,公式为: C(n, k) = n! / (k! × (n-k)!)
// 原始公式展开:C(n, k) = n × (n-1) × (n-2) × ... × (n-k+1)
// ---------------------------------
// 1 × 2 × 3 × ... × k
// 原始公式展开的推导过程:n! / (n-k)! = [n × (n-1) × (n-2) × ... × 3 × 2 × 1]
// / [(n-k) × (n-k-1) × ... × 3 × 2 × 1]
// 注意:分母中的 (n-k) × (n-k-1) × ... × 3 × 2 × 1 会与分子中对应的部分约掉。
// 约分后剩下:n × (n-1) × (n-2) × ... × (n-k+1)
// 关键思想:交替乘除
// 优点:中间结果始终是整数(因为组合数一定是整数)
// 避免大数运算(不需要计算阶乘)
// 数值稳定性好
num = num * (n - i + 1) / i;
}
arr[n][k] = num;
}
}
// 3.输出
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
if (j == arr[i].length - 1) {
// 不要在行末输出多余的空格
System.out.printf("%d", arr[i][j]);
} else {
System.out.printf("%d ", arr[i][j]);
}
}
System.out.println();
}
}
}