[WC2020] 猜数游戏 题解

一个(O(n^2log))垃圾做法

考虑建出一张有向图(G,) 有边(i->j)当且仅当存在一个正整数(m)使得(a_i^m)(a_j)在模(p)意义下同余(,)然后在图(G)上计算答案(.)

Part1:建图

subtask1:模数为奇质数

(p)意义下存在原根(,)设为(g.)

那么每个(a_i)都可以表示成(g^{k_i})

考虑求出一个数(a_i)的指标和(phi(p))(gcd)的值(k_i(k_i|phi(p)):)

显然(k_i)为满足(a_i^{phi(p)/k})(p)之后为(1)的最大的数(.)

枚举每个质因数(p)求它的次数(,)这个工作就可以在(O(d(phi(p)) imes log p)) 的时间内完成(.)

那么(,) (i->j)存在当且仅当(k_i|k_j.)

这样就可以(O(1)) (check)是否存在边(i->j)

subtask2:模数为奇质数(q)(t(t>1))次幂

(p^k)意义下也存在原根(.)

不难发现我们可以用同样的方法求出所有(k_i,)但是这回一个数可能会是(q)的倍数(,)我们记(a_i)的因数分解中存在的(q)的个数为(m_i.)

这次我们怎么(check) (i->j)是否可以连边呢(?)

首先如果(m_i=m_j=0,)那么就直接用上一个(subtask)的做法即可(.)

如果有一个(m=0,)而另一个(m ≠ 0,)那么边(i->j)不存在(.)

如果(m_i≠0,m_j≠0,)那么我们可以直接计算出可能使(a_i^z=a_j)的数字(z,z=m_j/m_i,)然后直接快速幂解决(.)

那么就可以(O(log p))的复杂度内(check)是否存在边(i->j)

如果害怕(T)飞的话可以求出原根用光速幂(,)不过(O(n^2log p))实际情况下也能过(.)


Part2:计算答案

建出图之后(,)我们考虑怎么计算答案(.)

考虑一个(a_i)对答案的贡献(.)

有一个想法是(a_i)在答案中存在的条件为当且仅当没有任何数能够表示出它(,)记这些数的个数为(cnt,)那么(a_i)对答案的贡献就是(2^{cnt}.)

但是这样做忽略了环的情况(,)只能获得(10pts.)

举个例子(,)如果(n=2,)(G)中存在边((1,2),(2,1),)如果按照这种算法计算出来的答案就是(2,)而正确答案是(3.)

那么这个问题怎么解决呢(?)

不难发现如果有一个强联通分量(S,) (S)内部的所有点必然是能两两连边的(,)所以我们可以给一个强联通分量内的点强制一个顺序(,)就可以正确的计算出答案了(.)

代码(:) 见云剪贴板


Bonus:如何解决(nleq 10^5,pleq 10^{18})

首先求出(phi(p),)(pollard-rho)分解质因数(,)并爆搜出(phi(p))的因子(.)

对于(gcd(a_i,p)≠1)(a_i)的贡献(,)

可以直接(O(nlog p imes K))暴力解决(,)其中(K)(phi(p))的质因数个数(.)

对于(gcd(a_i,p)=1)的数字(,)

首先用(O(nlog p imes K))的复杂度算出这(O(n))个数的指标(,)

然后以这些因子为下标运行狄利克雷前缀和即可(.)

复杂度(O(nlog p imes K + d(phi(p)) imes K))

代码(:) 见云剪贴板

原文地址:https://www.cnblogs.com/s-r-f/p/13581312.html