题解 【洛谷 P4345 [SHOI2015]超能粒子炮·改】
\(\large\mathcal{Description}\)
求:
\[\sum\limits_{i=0}^k {n \choose i} \bmod p.
\]
其中 \(p = 2333.\) 数据组数为 \(10^5.\)
\(n, k\le 10^{18}\)
\(\large\mathcal{Solution}\)
记
\[f(n, k) = \sum\limits_{i=0}^k {n \choose i} \bmod p = \sum\limits_{i=0}^k{\lfloor \frac np\rfloor \choose \lfloor \frac ip\rfloor}{n \bmod p \choose i \bmod p} \bmod p
\]
然后用类似整出分块的思想:
\[f(n, k) = {\lfloor \frac np\rfloor \choose 0}\sum\limits_{i=0}^{p-1} {n\bmod p \choose i} +{\lfloor \frac np\rfloor \choose 1}\sum\limits_{i=0}^{p-1} {n\bmod p \choose i} + \cdots + {\lfloor \frac np\rfloor \choose \lfloor \frac kp\rfloor-1}\sum\limits_{i=0}^{p-1} {n\bmod p \choose i}+{\lfloor \frac np\rfloor \choose \lfloor \frac kp\rfloor}\sum\limits_{i=0}^{k \bmod p} {n \bmod p \choose i}
\]
然后前面一段:
\[{\lfloor \frac np\rfloor \choose 0}\sum\limits_{i=0}^{p-1} {n\bmod p \choose i} +{\lfloor \frac np\rfloor \choose 1}\sum\limits_{i=0}^{p-1} {n\bmod p \choose i} + \cdots + {\lfloor \frac np\rfloor \choose \lfloor \frac kp\rfloor-1}\sum\limits_{i=0}^{p-1} {n\bmod p \choose i}
\]
也就是:
\[\sum\limits_{i=0}^{\lfloor \frac kp \rfloor}{\lfloor \frac np \rfloor \choose i}\times \sum\limits_{i=0}^{p-1} {n\bmod p \choose i} = f(\lfloor \frac np \rfloor, \lfloor \frac kp \rfloor) \times f(n \bmod p, p - 1)
\]
后面一段就是:
\[{\lfloor \frac np\rfloor \choose \lfloor \frac kp\rfloor}\sum\limits_{i=0}^{k \bmod p} {n \bmod p \choose i} = {\lfloor \frac np\rfloor \choose \lfloor \frac kp\rfloor}\times f(n \bmod p, k\bmod p)
\]
那么就有:
\[f(n, k) = f(\lfloor \frac np \rfloor, \lfloor \frac kp \rfloor) \times f(n \bmod p, p - 1) + {\lfloor \frac np\rfloor \choose \lfloor \frac kp\rfloor}\times f(n \bmod p, k\bmod p)
\]
我们把 \(n<p\) 且 \(k<p\) 时的 \(f(n, k)\) 都预处理出来,\({\lfloor \frac np\rfloor \choose \lfloor \frac kp\rfloor}\) 用卢卡斯定理处理,剩余部分递归即可。
\(\large\mathcal{Code}\)
#include <bits/stdc++.h>
#define reg register
using namespace std;
typedef long long LL;
typedef long double LDB;
const int P = 2333;
int T, f[P + 10][P + 10], C[P + 10][P + 10];
int Lucas(reg LL n, reg LL k)
{
if (!k) return 1;
return 1ll * Lucas(n / P, k / P) * C[n % P][k % P] % P;
}
int work(reg LL n, reg LL k)
{
if (!k) return 1;
if (n < P && k < P) return f[n][k];
return (1ll * f[n % P][P - 1] * work(n / P, k / P - 1) % P + 1ll * Lucas(n / P, k / P) * f[n % P][k % P] % P) % P;
}
int main()
{
scanf("%d", &T);
for (reg int i = 0; i <= P; ++ i)
{
C[i][0] = 1;
for (reg int j = 1; j <= i; ++ j) C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % P;
}
f[0][0] = 1;
for (reg int i = 0; i <= P; ++ i)
{
f[i][0] = 1;
for (reg int j = 1; j <= P; ++ j) f[i][j] = (f[i][j - 1] + C[i][j]) % P;
}
while (T -- )
{
LL n, k;
scanf("%lld %lld", &n, &k);
printf("%d\n", work(n, k));
}
return 0;
}