对于 gcd的询问,设值域为 V,询问次数为 Q, 有一种奇奇怪怪的时空复杂度都是 O(V+Q),即 O(V)——O(1)的做法。
解题思路:
把值域内的数 x都分解成 3个都不大于 √x的数相乘 (允许出现大于 √x的质数),步骤如下:
- 处理完所有小于 x的数
- 找到 x最小的质因子 p
- 将 xp分解的 3个数赋值入 x中,并把最小的数 a乘上 p
我们只需要证明这个最小的数 a×p≤x或 a×p是质数,因为其它 2 个数不是大质数就是小于 √xp, 肯定符合条件。
当 a=⧸1时,因为 p是 x的最小质因子,所以 p≤a, 又因为 a≤3√xp,
所以 p≤3√xp
p 非负,所以把根号去掉变成
p3≤xp
p4≤x
另外,p×3√xp明显是递增的(你也可以在这里直观感受一下
当 p 取最大值 4√x时,a×p≤4√x×3√x4√x=3√x×4√x2=3√x32=√x
特殊的,当 a=1时,p显然是质数,即使大于 √x满足我们要求的性质
同时,上面的操作明显可以用线性筛完成
处理完之后,所有数基本都在 √V以内了,那么我们就可以打个 √V×√V的 gcd的表,每次求 gcd是可以 O(1)的,gcd[i][j]=gcd[j][i]=gcd[i mod j][j]。根据辗转相除法,这显然正确。查询 2 个大数 x,y的 gcd时,找出 a 的分解的 3个数 num1,num2,num3,对于每个 num,如果是质数直接判断能不能整除 b,否则求 gcd[numi][b mod numi],然后让 b除以这个数就行了。
1 条评论
skydogli · 2019年10月7日 10:00 下午
其实现在觉得这玩意好鸡肋啊,带个巨大常数,而在批量用 gcd 的时候复杂度大多数不是 log 的,所以朴素 gcd 爆踩这个算法。