【洛谷P4345】超能粒子炮·改
题目
题目链接:https://www.luogu.com.cn/problem/P4345
曾经发明了脑洞治疗仪与超能粒子炮的发明家 SHTSC 又公开了他的新发明:超能粒子炮・改——一种可以发射威力更加强大的粒子流的神秘装置。
超能粒子炮・改相比超能粒子炮,在威力上有了本质的提升。它有两个参数 \(n,k\) ,它会向每个编号为 \(0\) 到 \(k\) (包含两端)的位置 \(i\) 发射威力为 \(C_{n}^{i} \bmod 2333\) 的粒子流。
现在 SHTSC 给出了他的超能粒子炮・改的参数,让你求出其发射的粒子流的威力之和除以 \(2333\) 所得的余数。
\(t \leq 100000,n,k \le 10^{18}\)。
思路
约定以下以下所有除法均为整除(下取整)。
题目所求为
\[f_{n,k}=\sum^{k}_{i=0}\binom{n}{i}=\sum^{k}_{i=0}\binom{n\div p}{i\div p}\binom{n\bmod p}{i\bmod p}
\]
看见除法不难想到整除分块
\[=\left(\sum^{p-1}_{i=0}\binom{n\div p}{i}\right)\left(\sum_{i=0}^{k\div p-1}\binom{n\div p}{i}\right)+\binom{n\div p}{k\div p}\left(\sum^{k\bmod p}_{i=0}\binom{n\bmod p}{i}\right)
\]
令 \(g_{i,j}=\sum^{j}_{k=0}\binom{k}{i}\)
\[=g_{n\bmod p,p-1}f_{n\div p,k\div p-1}+\binom{n\div p}{k\div p}g_{n\bmod p,k\bmod p}
\]
因为下标全部小于 \(p\),所以 \(g\) 可以预处理出来,然后组合数用 Lucas 求,\(f\) 递归求即可。
时间复杂度 \(O(p^2+Q\log^2 n)\)。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll p=2333;
int Q;
ll a,b,C[p][p],g[p][p];
ll lucas(ll n,ll m)
{
if (n<p && m<p) return C[n][m];
return lucas(n/p,m/p)*C[n%p][m%p]%p;
}
ll calc(ll n,ll k)
{
if (k<0) return 0;
if (n<p && k<p) return g[n][k];
return (g[n%p][p-1]*calc(n/p,k/p-1)+lucas(n/p,k/p)*g[n%p][k%p])%p;
}
int main()
{
for (int i=0;i<p;i++)
C[i][0]=g[i][0]=g[0][i]=1;
for (int i=1;i<p;i++)
for (int j=1;j<p;j++)
{
C[i][j]=(C[i-1][j]+C[i-1][j-1])%p;
g[i][j]=(C[i][j]+g[i][j-1])%p;
}
scanf("%d",&Q);
while (Q--)
{
scanf("%lld%lld",&a,&b);
printf("%lld\n",calc(a,b));
}
return 0;
}