【BZOJ4591】超能粒子炮·改(Lucas定理,组合计数)
题意:
曾经发明了脑洞治疗仪&超能粒子炮的发明家SHTSC又公开了他的新发明:超能粒子炮·改--一种可以发射威力更加
强大的粒子流的神秘装置。超能粒子炮·改相比超能粒子炮,在威力上有了本质的提升。它有三个参数n,k。它会
向编号为0到k的位置发射威力为C(n,k) mod 2333的粒子流。现在SHTSC给出了他的超能粒子炮·改的参数,让你求
其发射的粒子流的威力之和模2333。
n,k<=10^18
cas<=10^5
思路:WYZ作业
应该是一道在草稿纸上就能完成大半部分的题
设S(n,k)=Σ C(n,i) i=0..k
先运用Lucas定理将C(n,m)表示为C(n div mo,m div mo)*C(n mod mo,m mod mo)
将其一项一项写出我们可以发现,i=0..p-1可以分成一组,p..2p-1可以分成一组……一共可以分成k div mo-1组,每一组都有一些重复的部分
这些整组的和整理后为S(n div mo,k div mo-1)*S(n mod mo,mo-1)
还有最后若干无法凑成整组的项,可以发现他们的系数都是C(n div mo,k div mo)
这些项的和为C(n div mo,k div mo)*S(n mod mo,k mod mo)
两部分加起来就是S(n,k)
1 const mo=2333; 2 var s,c:array[0..mo,0..mo]of int64; 3 cas,i,j,v:longint; 4 n,k:int64; 5 6 function ask(n,k:int64):int64; 7 var a,b:int64; 8 begin 9 if (n<k)or(k<0) then exit(0); 10 if n<mo then exit(c[n,k]); 11 a:=n div mo; b:=k div mo; 12 exit(ask(a,b)*c[n mod mo,k mod mo] mod mo); 13 end; 14 15 function clac(n,k:int64):int64; 16 var a,b:int64; 17 begin 18 if k<0 then exit(0); 19 a:=n div mo; b:=k div mo; 20 exit((clac(a,b-1)*s[n mod mo,mo-1] 21 +ask(a,b)*s[n mod mo,k mod mo]) mod mo); 22 end; 23 24 begin 25 assign(input,'bzoj4591.in'); reset(input); 26 assign(output,'bzoj4591.out'); rewrite(output); 27 c[0,0]:=1; 28 c[1,0]:=1; c[1,1]:=1; 29 for i:=2 to mo do 30 begin 31 c[i,0]:=1; 32 for j:=1 to i do c[i,j]:=(c[i-1,j-1]+c[i-1,j]) mod mo; 33 end; 34 for i:=0 to mo-1 do 35 begin 36 s[i,0]:=1; 37 for j:=1 to mo-1 do s[i,j]:=(s[i,j-1]+c[i,j]) mod mo; 38 end; 39 read(cas); 40 for v:=1 to cas do 41 begin 42 read(n,k); 43 writeln(clac(n,k)); 44 end; 45 close(input); 51 close(output); 52 end.
null