题目链接:
[
S
H
O
I
2015
]
超
能
粒
子
炮
⋅
改
\rm [SHOI2015]超能粒子炮·改
[SHOI2015]超能粒子炮⋅改
感谢
V
e
n
u
s
\rm Venus
Venus 神仙帮助完成
LaTeX
\LaTeX
LATEX 公式
显然题目让我们求的是
[
∑
i
=
0
k
(
n
i
)
]
%
p
\rm \left[\sum\limits_{i=0}^k\binom ni\right]\%p
[i=0∑k(in)]%p 的值,其中
p
=
2333
\rm p=2333
p=2333
设
sum
(
n
,
k
)
=
[
∑
i
=
0
k
(
n
i
)
]
%
p
\rm \operatorname{sum}(n,k)=\left[\sum\limits_{i=0}^k\binom ni\right]\%p
sum(n,k)=[i=0∑k(in)]%p
然后我们开始推式子(大波
LaTeX
\LaTeX
LATEX 公式警告):
sum ( n , k ) = [ ∑ i = 0 k ( n i ) ] % p (为保证界面美观,以下省略%p) = ∑ i = 0 k ( n / p i / p ) ( n % p i % p ) (卢卡斯定理) = [ ∑ i = 0 p − 1 ( n / p 0 ) ( n % p i ) ] + [ ∑ i = 0 p − 1 ( n / p 1 ) ( n % p i ) ] + ⋯ + [ ∑ i = 0 p − 1 ( n / p k / p − 1 ) ( n % p i ) ] + [ ∑ i = 0 k % p ( n / p k / p ) ( n % p i ) ] (整除分块) = [ ( n / p 0 ) ∑ i = 0 p − 1 ( n % p i ) ] + [ ( n / p 1 ) ∑ i = 0 p − 1 ( n % p i ) ] + ⋯ + [ ( n / p k / p − 1 ) ∑ i = 0 p − 1 ( n % p i ) ] + [ ( n / p k / p ) ∑ i = 0 k % p ( n % p i ) ] = [ ∑ i = 0 p − 1 ( n % p i ) ] × [ ∑ j = 0 k / p − 1 ( n / p j ) ] + ( n / p k / p ) ∑ i = 0 k % p ( n % p i ) \begin{aligned} \rm \operatorname{sum}(n,k) & =\rm \left[ \sum_{i=0}^k\binom ni \right] \%p \quad\color{#66ccff}\textbf{(为保证界面美观,以下省略\%p)}\\ & =\rm \sum_{i=0}^k\binom{n/p}{i/p}\binom{n\%p}{i\%p} \color{#66ccff}\textbf{(卢卡斯定理)}\\ & =\rm \left[ \sum_{i=0}^{p-1}\binom{n/p}0\binom{n\%p}i\right] +\left[\sum_{i=0}^{p-1}\binom{n/p}1\binom{n\%p}i\right]+\cdots \\ & \rm \quad\ +\left[\sum_{i=0}^{p-1}\binom{n/p}{k/p-1} \binom{n\%p}i\right] +\left[\sum_{i=0}^{k\% p}\binom{n/p}{k/p}\binom{n\%p}i \right] \color{#66ccff}\textbf{(整除分块)}\\ & =\rm \left[\binom{n/p}0\sum_{i=0}^{p-1}\binom{n\%p}i\right] +\left[\binom{n/p}1\sum_{i=0}^{p-1}\binom{n\%p}i\right]+\cdots \\ & \rm\quad\ +\left[\binom{n/p}{k/p-1}\sum_{i=0}^{p-1}\binom{n\%p}i\right] +\left[\binom{n/p}{k/p}\sum_{i=0}^{k\%p}\binom{n\%p}i\right] \\ & =\rm \left[\sum_{i=0}^{p-1}\binom{n\%p}i\right] \times\left[\sum_{j=0}^{k/p-1}\binom{n/p}j\right] +\binom{n/p}{k/p}\sum_{i=0}^{k\%p}\binom{n\%p}i \end{aligned} sum(n,k)=[i=0∑k(in)]%p(为保证界面美观,以下省略%p)=i=0∑k(i/pn/p)(i%pn%p)(卢卡斯定理)=[i=0∑p−1(0n/p)(in%p)]+[i=0∑p−1(1n/p)(in%p)]+⋯ +[i=0∑p−1(k/p−1n/p)(in%p)]+⎣⎡i=0∑k%p(k/pn/p)(in%p)⎦⎤(整除分块)=[(0n/p)i=0∑p−1(in%p)]+[(1n/p)i=0∑p−1(in%p)]+⋯ +[(k/p−1n/p)i=0∑p−1(in%p)]+⎣⎡(k/pn/p)i=0∑k%p(in%p)⎦⎤=[i=0∑p−1(in%p)]×⎣⎡j=0∑k/p−1(jn/p)⎦⎤+(k/pn/p)i=0∑k%p(in%p)
再套用一下
sum
\operatorname{sum}
sum 的定义就有:
sum
(
n
,
k
)
=
[
sum
(
n
%
p
,
p
−
1
)
×
sum
(
n
/
p
,
k
/
p
−
1
)
+
(
n
/
p
k
/
p
)
sum
(
n
%
p
,
k
%
p
)
]
%
p
\rm \operatorname{sum}(n,k)= \left [\operatorname{sum}(n\%p,p-1) \times\operatorname{sum}(n/p,k/p-1) +\binom{n/p}{k/p}\operatorname{sum}(n\%p,k\%p)\right] \%p
sum(n,k)=[sum(n%p,p−1)×sum(n/p,k/p−1)+(k/pn/p)sum(n%p,k%p)]%p
化简完毕。那么各部分如何处理呢?
sum ( n % p , p − 1 ) , sum ( n % p , k % p ) 的 参 数 都 小 于 p , 可 以 预 处 理 出 来 ; 2333 是 质 数 , 所 以 ( n / p k / p ) 显 然 可 以 用 L u c a s 搞 出 来 ; sum ( n / p , k / p − 1 ) 可 以 递 归 求 解 。 \begin{aligned} & \rm \operatorname{sum}(n\%p,p-1),\operatorname{sum}(n\%p,k\%p) 的参数都小于 p ,可以预处理出来; \\ & \rm 2333是质数,所以\binom{n/p}{k/p}显然可以用Lucas搞出来; \\ & \rm \operatorname{sum}(n/p,k/p-1)可以递归求解。 \end{aligned} sum(n%p,p−1),sum(n%p,k%p)的参数都小于p,可以预处理出来;2333是质数,所以(k/pn/p)显然可以用Lucas搞出来;sum(n/p,k/p−1)可以递归求解。
代码
#include<cstdio>
#include<cctype>
#define getc (l==r&&(r=(l=f)+fread(f,1,1<<21,stdin),l==r)?EOF:*l++)
//fread优化快读
typedef long long ll;
const int p=2333;
char f[1<<21],*l=f,*r=f;
inline ll read() { //快读
ll x=0; char ch=getc;
while (!isdigit(ch)) ch=getc;
while (isdigit(ch)) { x=x*10+(ch^48); ch=getc; }
return x;
}
int c[p][p],s[p][p];
void work() {
//杨辉三角预处理组合数
for (int i=0; i<p; ++i) c[i][0]=c[i][i]=s[i][0]=1;
for (int i=1; i<p; ++i)
for (int j=1; j<i; ++j)
c[i][j]=(c[i-1][j]+c[i-1][j-1])%p;
//前缀和预处理
for (int i=0; i<p; ++i)
for (int j=1; j<p; ++j)
s[i][j]=(s[i][j-1]+c[i][j])%p;
}
int C(ll n,ll m) {
return m?C(n/p,m/p)*c[n%p][m%p]%p:1; //卢卡斯
}
int S(ll n,ll m) {
if (!n||!m) return 1;
if (n<p&&m<p) return s[n][m];
int ans=(m>=p?s[n%p][p-1]*S(n/p,m/p-1)%p:0);
(n/p>=m/p)&&(ans+=C(n/p,m/p)*s[n%p][m%p]%p);
return ans%p;
}
int main() {
work();
int T=read();
while (T--) {
ll n=read(),m=read();
printf("%d\n",S(n,m));
}
}