You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

64 lines
2.9 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <bits/stdc++.h>
using namespace std;
const int N = 150, mod = 1000;
int k, x;
int f[1010][110][N];
// 前两维组合数C(n-1,k-1),其中n最大值是1000k最大值是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;
}