好玩的推式子
题目描述
曾经发明了脑洞治疗仪与超能粒子炮的发明家 SHTSC 又公开了他的新发明:超能粒子炮・改——一种可以发射威力更加强大的粒子流的神秘装置。
超能粒子炮・改相比超能粒子炮,在威力上有了本质的提升。它有两个参数 nnn、kkk,它会向每个编号为 000 到 kkk(包含两端)的位置 iii 发射威力为 Cni mod 2333\mathrm{C}_n^i \bmod 2333Cnimod2333 的粒子流。
现在 SHTSC 给出了他的超能粒子炮・改的参数,让你求出其发射的粒子流的威力之和除以 233323332333 所得的余数。
输入格式:
第一行一个整数 ttt 表示数据组数。
之后 ttt 行,每行两个整数 nnn、kkk,含义如题面描述。输出格式:
ttt 行,每行一个整数,表示其粒子流的威力之和模 233323332333 的值。
输入输出样例
输入样例:
3 5 5 10 7 1145 14
输出样例:
32 968 763
数据范围与约定
对于 10%10\%10% 的数据,t=1t=1t=1,n,k≤1000n,k\le 1000n,k≤1000;
对于 30%30\%30% 的数据,t=1t=1t=1,n,k≤1000000n,k\leq 1000000n,k≤1000000;
对于 50%50\%50% 的数据,t=1t=1t=1,n≤1018,k≤1000n\le 10^{18},k\le 1000n≤1018,k≤1000;
对于 70%70\%70% 的数据,t≤100t\le 100t≤100,n,k≤1018n,k\le 10^{18}n,k≤1018;
对于 100%100\%100% 的数据,t≤100000t\le 100000t≤100000,n,k≤1018n,k\le 10^{18}n,k≤1018。
题解:
注:本文中所有的除法 /// 都向下取整,所有的百分号 %\%% 都表示取模。
这个题求的是 ∑i=0kCni mod 2333\sum_{i=0}^k\mathrm{C}_n^i\bmod 2333∑i=0kCnimod2333。但是模数是 233323332333 因此可以考虑 Lucas 定理,即 Cnm%p=Cn%pm%pCn/pm/p\mathrm{C}_n^m\% p=\mathrm{C}_{n\% p}^{m\% p}\mathrm{C}_{n/p}^{m/p}Cnm%p=Cn%pm%pCn/pm/p。
我们把上面的和式推导一下,则为
∑i=0kCn/2333i/2333Cn%2333i%2333
\sum_{i=0}^k\mathrm{C}_{n/2333}^{i/2333}\mathrm{C}_{n\%2333}^{i\%2333}
i=0∑kCn/2333i/2333Cn%2333i%2333
然后我们发现,整个过程中 n/2333n/2333n/2333 和 n%2333n\% 2333n%2333 是不变的。只需要关注 i/2333i/2333i/2333 和 i%2333i\%2333i%2333 的变化规律。
而对于连续的 i∈[2333k,2333k+2333)i\in[2333k,2333k+2333)i∈[2333k,2333k+2333) 它们的 i/2333i/2333i/2333 是相同的,i%2333∈[0,2333)i\%2333\in[0,2333)i%2333∈[0,2333),所以我们把需要求和的 kkk 个数分成 ⌈k2333⌉\left\lceil\frac{k}{2333}\right\rceil⌈2333k⌉ 段。其中前 ⌊k2333⌋\left\lfloor\frac{k}{2333}\right\rfloor⌊2333k⌋ 段一定是完整的,因此可以表示为
∑t=0⌊k2333⌋Cn/2333t∑i=02332Cn%2333i+∑i=k−k%2333kCn/2333i/2333Cn%2333i%2333
\sum_{t=0}^{\left\lfloor\frac{k}{2333}\right\rfloor}\mathrm{C}_{n/2333}^t\sum_{i=0}^{2332}\mathrm{C}_{n\%2333}^i+\sum_{i=k-k\%2333}^k\mathrm{C}_{n/2333}^{i/2333}\mathrm{C}_{n\%2333}^{i\%2333}
t=0∑⌊2333k⌋Cn/2333ti=0∑2332Cn%2333i+i=k−k%2333∑kCn/2333i/2333Cn%2333i%2333
对于加号后面的式子,i/2333=0i/2333=0i/2333=0,所以是对后面一个式子求和,因此可以用杨辉三角预处理,并求出前缀和,O(1)O(1)O(1) 解决。
对于中间一个式子 ∑i=02332Cn%2333i\sum_{i=0}^{2332}\mathrm{C}_{n\%2333}^i∑i=02332Cn%2333i ,因为 n%2333<2333n\%2333<2333n%2333<2333 ,同理用杨辉三角。
令
∑i=02332Cn%2333i=S, ∑i=k−k%2333kCn/2333i/2333Cn%2333i%2333=A
\sum_{i=0}^{2332}\mathrm{C}_{n\%2333}^i=S,\\\ \sum_{i=k-k\%2333}^k\mathrm{C}_{n/2333}^{i/2333}\mathrm{C}_{n\%2333}^{i\%2333}=A
i=0∑2332Cn%2333i=S, i=k−k%2333∑kCn/2333i/2333Cn%2333i%2333=A
则原式为
S∑t=0⌊k2333⌋Cn/2333t+A
S\sum_{t=0}^{\left\lfloor\frac{k}{2333}\right\rfloor}\mathrm{C}_{n/2333}^t+A
St=0∑⌊2333k⌋Cn/2333t+A
对于剩下的一个式子,又转化为了一个求和的子问题,因此我们递归解决。递归的边界是 k<2333k<2333k<2333。
因此可以在 23332+O(tlogk)2333^2+O(t\log k)23332+O(tlogk) 的时间复杂度内解决这个问题。
Code:
#include<cstdio>
#define ll long long
ll C[2333][2333];
ll calc(ll n,ll t)//0~t的C_n^t
{
ll ans=0,p=n%2333;
if(t/2333)
ans=C[p][p]*calc(n/2333,t/2333-1)%2333;
else
return C[p][t%2333];
ll a=n/2333,b=t/2333,tmp=1;
while(a>=2333||b>=2333)
{
if(b%2333)
tmp=tmp*(C[a%2333][b%2333]-C[a%2333][b%2333-1]+2333)%2333;
a/=2333,b/=2333;
}
if(b)
tmp=tmp*(C[a][b]-C[a][b-1]+2333)%2333;
ans=(ans+C[p][t%2333]*tmp)%2333;
return ans;
}
int main()
{
C[0][0]=1;
for(int i=1;i<=2332;++i)
{
C[i][0]=1;
for(int j=1;j<=i;++j)
C[i][j]=(C[i-1][j-1]+C[i-1][j])%2333;
}
for(int i=0;i<=2332;++i)
for(int j=1;j<=2332;++j)
C[i][j]=(C[i][j-1]+C[i][j])%2333;
int T;
ll n,k;
scanf("%d",&T);
while(T--)
{
scanf("%lld%lld",&n,&k);
printf("%lld\n",calc(n,k));
}
return 0;
}