题目大意
给定 q ( 1 ≤ q ≤ 1 0 6 ) q(1 \leq q \leq 10^6) q(1≤q≤106),每次输入两个数 n , m ( 1 ≤ n ≤ 2 63 − 1 , 0 ≤ m ≤ m ) n,m(1 \leq n \leq 2^{63} - 1, 0 \leq m \leq m) n,m(1≤n≤263−1,0≤m≤m),若 C n m ≤ 2 63 − 1 C_n^m \leq 2^{63} - 1 Cnm≤263−1 输出 C n m C_n^m Cnm,否则输出0。
解题思路
在杨辉三角预处理组合数时,到第70项以后开始就出现了大于 2 63 − 1 2^{63}-1 263−1 的数,第 1000 项的第 9 个组合数就已经超过范围了。而根据杨辉三角的递推式 C n m = C n − 1 m − 1 + C n − 1 m C_n^m = C_{n - 1}^{m - 1} + C_{n - 1}^{m} Cnm=Cn−1m−1+Cn−1m,若上面两项的其中一项已经溢出,那么下面的项后面就不需要再递推了。
但是即使这样数组也不能开太大,于是想了一个思路,就是先找到 C n 4 C_n^4 Cn4 不溢出的分解数,即145056,然后再找到 C n 3 C_n^3 Cn3 不溢出的分界数 4801280,大于4801280的数实际上只可能有三种方式,特判即可。小于145056的直接打表,但不是全部的表,1000项之后的表只需要开前十项的空间。
记得开 _ _ i n t 128 \_\_int128 __int128。
#include <bits/stdc++.h>
using namespace std;
#define ENDL "\n"
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const double eps = 1e-4;
const int Mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const int maxn = 150000;
const ull INF = ~0ULL;
__int128_t C[1005][1005];
__int128_t C2[maxn][11];
int len[maxn];
void write(__int128_t x) {
if (x < 0) cout << "-", x = -x;
if (x < 10) {
cout << (char)('0' + x);
return;
}
write(x / 10);
cout << (char)('0' + x % 10);
}
void init() {
C[0][0] = 1;
len[0] = 0;
for (int i = 1; i <= 145056; i++) {
if (i < 1000) {
C[i][0] = 1;
for (int j = 1; j <= i; j++) {
C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
if (C[i][j] > INF) {
len[i] = j - 1;
break;
}
}
} else if (i == 1000) {
C2[i][0] = 1;
for (int j = 1; j <= i; j++) {
C2[i][j] = C[i - 1][j] + C[i - 1][j - 1];
if (C2[i][j] > INF) {
len[i] = j - 1;
break;
}
}
} else {
C2[i][0] = 1;
for (int j = 1; j <= i; j++) {
C2[i][j] = C2[i - 1][j] + C2[i - 1][j - 1];
if (C2[i][j] > INF) {
len[i] = j - 1;
break;
}
}
}
if (!len[i]) len[i] = i;
}
// for (int i = 1; i <= 1000; i++) cout << len[i] << endl;
}
__int128_t CN2(__int128_t x) {
return x * (x - 1) / 2; }
__int128_t CN3(__int128_t x) {
return x * (x - 1) * (x - 2) / 6; }
__int128_t CN4(__int128_t x) {
return x * (x - 1) * (x - 2) * (x - 3) / 24; }
// 0 - 145056
// 145057 - 4801280 最大C_i^3
// 4801281 检测C_i^2是否越界
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
// ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
ll n, m;
ll s = 1e10;
init();
int up = 1e6;
for (int i = 1; i <= up; i++) {
cin >> n >> m;
if (m > n / 2) m = n - m;
if (n <= 145056) {
if (m <= len[n]) {
if (n < 1000)
write(C[n][m]), cout << ENDL;
else
write(C2[n][m]), cout << ENDL;
} else
cout << 0 << ENDL;
} else if (n > 145056 && n <= 4801280) {
if (m == 3) {
if (CN3(n) <= INF)
write(CN3(n)), cout << ENDL;
else
cout << 0 << ENDL;
} else if (m == 2)
write(CN2(n)), cout << ENDL;
else if (m == 1)
cout << n << ENDL;
else if (m == 0)
cout << 1 << ENDL;
else
cout << 0 << ENDL;
} else if (n >= 4801281 && n < s) {
if (m == 2) {
if (CN2(n) <= INF)
write(CN2(n)), cout << ENDL;
else
cout << 0 << ENDL;
} else if (m == 1)
cout << n << ENDL;
else if (m == 0)
cout << 1 << ENDL;
else
cout << 0 << ENDL;
} else {
//只有CN1和CN0
if (m == 1)
cout << n << ENDL;
else if (m == 0)
cout << 1 << ENDL;
else
cout << 0 << ENDL;
}
}
return 0;
}