【集训队试题 礼物】数论、递归求值

题目见H8OJ 2142

http://www.zybbs.org/JudgeOnline/problem.php?id=2142

综合性比较强的求值题(这个名字好像不怎么样。。)

my solution:

 

本题有几个关键点,主要都是基于mod的快速求值

a.       列出目标式: t1

b.       p分解质因数p =t2ai为质数)(共t个质因子)

c.       加速如下形式的式子的求值

S = K! mod (ai^bi) a为质数)

即对pt个质因子分别求值

目标式中在分子的阶乘式直接乘,在分母的则取其乘法逆元

d.       用中国剩余定理或直接累加将t个取模后的值合并得到答案

大概的步骤就是这样,但还有两个非常关键的问题还没有解决

A. 如何对分母的阶乘式取乘法逆元

由于式子中不是所有的项都与ai^bi互质,所以不能直接用欧拉定理,那我们就将所有分子分母中含ai的质因子提取出来,先约分再最后一次快速幂求出值来,提取完ai剩下的部分都与ai^bi互质,就能直接用欧拉定理求解

B. 如何加速下式

S = K! mod (ai^bi) a为质数)

的求值

mo = ai^bi

可以发现

1*2*…*(mo-1) mod mo

= (1 + mo)*(2 + mo)*…*(mo-1 + mo) mod mo

= (1 + mo*2)*(2 + mo*2)*…*(mo-1 + mo*2) mod mo

=(1 + mo*i)*(2 + mo*i)*…*(mo-1 + mo*i) mod mo

那么

1*2*…*K mod mo

=[1*2*…*(mo-1)]^(K div mo)

*mo*(2*mo)*(3*mo)*…*[(K div mo)*mo]

*(K div mo*mo+1)*(K div mo*mo+2)*…*K

其实就是将所以乘积mod mo相同的(1+i*mo)*(2+i*mo)*…*(mo-1 + i*mo)全部放到一起,i*mo放到一起,最后剩下的一部分放到一起

其中第一部分可以预处理+快速幂解决,第三部分可以朴素地算,第二部分提出一个mo后变成1*2*…*(K div mo),可以递归地计算

由于每次递归都将问题规模缩为1/ai,所以递归次数为log级,每层的复杂度为   O(mo + logK),总的复杂度就还是很低的,可以秒杀所有数据

至此,问题其实还并没有完全解决,我们还遗留了一些小问题没有解决。因为实际上由于我们要提出所有含ai的质因数,在上述快速求值的过程中,我们不能直接提出mo(实际上就是ai^bi),而只能提出ai,虽然大体的递归计算过程差不多,但还是引发了一些细节问题,有如下几个

A. 我们求出的1*2*…*(mo-1) mod momod ai = 0的项不能算进来,因为我们在对上面第二部分式子提出ai并递归计算的时候,实际上我们或直接或间接地将含有ai的项全都算进来了

B. 我们在上面的式子的第三部分朴素的计算部分中,mod ai = 0的项也不能算进来,理由同上

现在,问题才算基本完美解决,这里顺便提一下,最后那个合并答案的部分其实直接朴素地加是没有问题的,复杂度是有保证的,证明思路大概就是每次合并最多加当前这个ai^bi次,而即便是这样,最多也就加m*ai^bi次,这个次数其实是很少的,完全不会影响算法的效率

代码:

 

我一开始直接以ai分的段,居然也ac了。。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值