#include using namespace std; const int N = 150, mod = 1000; int k, x; int f[1010][110][N]; // 前两维:组合数C(n-1,k-1),其中n最大值是1000,k最大值是100,还都减了1, 所以这么开就足够大了,再+10肯定够了 // 第三维: 高精度的结果 // 快速幂 int qmi(int a, int b, int p) { int res = 1; while (b) { if (b & 1) res = res * a % p; a = a * a % p; b >>= 1; } return res; } // 因为本题需要计算组合数,就是在(i,j)确定下的第三维数组空间保存结果 void add(int a[], int b[], int c[]) { for (int i = 0, t = 0; i < N; i++) { // 开的静态数组 N的长度足够(150是通过calc估算出的139上浮得到的极限值) // 不用对比两个高精度的长度,全部当做150极限来看,也没多大 t += a[i] + b[i]; c[i] = t % 10; t /= 10; } } int main() { cin >> k >> x; // k个数字, g(x)=x^x 指引我们使用快速幂 // 技巧:在求快速幂+模时,时刻注意取模 // 比如先把底、幂次取模后再计算快速幂 int n = qmi(x % mod, x % mod, mod); // 递推求组合数,一直递推到C(n,k) for (int i = 0; i <= n; i++) for (int j = 0; j <= min(i, k); j++) // 孙猴子再厉害,也不能翻出如来佛的五指山,k<=i if (!j) f[i][j][0] = 1; // C(i,0)=1,所以C(i,0)指向的其实是一个一维数组,也就是C(i,0)的高精度结果。此结果=1.按高精度来说,就是a[0]=1 else // C(i,j)=C(i-1,j)+C(i-1,j-1) // 左侧:从i个小球中选择j个小球的方法数 // 右侧:(1) 不选第1个,那么在剩余i-1个小球中选择j个小球的方法数 // 右侧:(2) 选择第1个,那么在剩余i-1个小球中选择j-1个小球的方法数 // 再结合加法原理,即可得到上面的公式,这个公式可以用于递推 // 这个三维数组+高精度用的漂亮啊! // f[][][]是三维数组,f[i - 1][j] 是指在i-1个中选择j个有多少种办法,其实结果是存在第三维中, // f[i - 1][j]指向的是一维数组,也就是f[i-1][j]的方法数的高精度结果 // 理解为add(a[],b[],c[]);也就是简单的高精度加法 add(f[i - 1][j], f[i - 1][j - 1], f[i][j]); // 上面多求了一些数据出来,我们只需要: C(n - 1, k - 1) // 将前二维数组简写为g,此处g为一个指针,指向的是f[n-1][k-1]指向的高精度数组对应的一维数组 int *g = f[n - 1][k - 1]; int i = N - 1; // 最高位 while (!g[i]) i--; // 去除前导0 while (i >= 0) cout << g[i--]; // 倒序输出 return 0; }