Description
![JZOJ6782.【NOI2020.08.06模拟】wlwl_第1张图片](http://img.e-com-net.com/image/info8/c73e393c7a28425e995b38203af22a76.jpg)
- n ≤ 1 e 5 , p ≤ 1 e 18 n\le1e5,p\le1e18 n≤1e5,p≤1e18
Solution
- 跟昨天的WC T2用同样的套路来转化??!可惜没有提前做到这场模拟赛,血亏。
- 简单的数论都不太熟练,做同余问题连智商都没有了。
- 首先假设 g g g为原根,有 g x = a g^x=a gx=a,设 a o r d ( a ) = 1 a^{ord(a)}=1 aord(a)=1,那么 g x ∗ o r d ( a ) = 1 g^{x*ord(a)}=1 gx∗ord(a)=1,所以 ( p − 1 ) ∣ x ∗ o r d ( a ) (p-1)|x*ord(a) (p−1)∣x∗ord(a),把 x x x除到左边,可以得到 p − 1 ( x , p − 1 ) ∣ o r d ( a ) \frac{p-1}{(x,p-1)}|ord(a) (x,p−1)p−1∣ord(a),所以最小的 o r d ( a ) ord(a) ord(a)满足 o r d ( a ) = p − 1 ( x , p − 1 ) ord(a)=\frac{p-1}{(x,p-1)} ord(a)=(x,p−1)p−1。
- 接下来我们考虑 g x = a , g y = b g^x=a,g^y=b gx=a,gy=b,解 a i = b j a^i=b^j ai=bj,那么 x i = y j ( % ( p − 1 ) ) xi=yj(\%(p-1)) xi=yj(%(p−1)),同理 ( y , p − 1 ) ∣ x i (y,p-1)|xi (y,p−1)∣xi,所以 i = ( y , p − 1 ) ( x , y , p − 1 ) i=\frac{(y,p-1)}{(x,y,p-1)} i=(x,y,p−1)(y,p−1)最小。
- ( x , p − 1 ) = p − 1 o r d ( a ) (x,p-1)=\frac{p-1}{ord(a)} (x,p−1)=ord(a)p−1, i = p − 1 o r d ( b ) ( p − 1 o r d ( a ) , p − 1 o r d ( b ) ) = p − 1 o r d ( b ) p − 1 l c m ( o r d ( a ) , o r d ( b ) ) = l c m ( o r d ( a ) , o r d ( b ) ) o r d ( b ) = o r d ( a ) ( o r d ( a ) , o r d ( b ) ) i=\frac{\frac{p-1}{ord(b)}}{(\frac{p-1}{ord(a)},\frac{p-1}{ord(b)})}=\frac{\frac{p-1}{ord(b)}}{\frac{p-1}{lcm(ord(a),ord(b))}}=\frac{lcm(ord(a),ord(b))}{ord(b)}=\frac{ord(a)}{(ord(a),ord(b))} i=(ord(a)p−1,ord(b)p−1)ord(b)p−1=lcm(ord(a),ord(b))p−1ord(b)p−1=ord(b)lcm(ord(a),ord(b))=(ord(a),ord(b))ord(a)。
- i m i n ∗ j m i n = o r d ( a ) o r d ( b ) ( o r d ( a ) , o r d ( b ) ) 2 i_{min}*j_{min}=\frac{ord(a)ord(b)}{(ord(a),ord(b))^2} imin∗jmin=(ord(a),ord(b))2ord(a)ord(b)。
- 考虑在质因数个数上做一个类似高维后缀和的东西,然后再高维差分(相当于取min)那么枚举 d = ( o r d ( a ) , o r d ( b ) ) , d ∣ p − 1 d=(ord(a),ord(b)),d|p-1 d=(ord(a),ord(b)),d∣p−1,就可以直接计算答案。
- o r d ( a ) ord(a) ord(a)可以直接试除法找到一个最小的 a i = 1 , i ∣ p − 1 a^{i}=1,i|p-1 ai=1,i∣p−1,每一次枚举 p − 1 p-1 p−1的一个质因子即可,做pollard_rho分解质因数。
#include
#include
#include
#include
#define maxn 100005
#define maxf 1000005
#define ll long long
#define ull unsigned long long
#define maxc 20
using namespace std;
int n,i,j,k,a[maxn];
ll P,x;
ll mul(ll x, ll y, ll p){
ll t=(x*y-(ll)((long double)x/p*y)*p)%p;
if (t<0) return t+p; return t;
}
ll ksm(ll x,ll y,ll p){ll s=1;for(;y;y/=2,x=mul(x,x,p)) if (y&1) s=mul(s,x,p); return s;}
ull sd;ll rd(){sd^=sd>>13,sd^=sd<<7,sd^=sd>>23;return sd>>1;}
ll gcd(ll x,ll y){return (x%y==0)?y:gcd(y,x%y);}
int mr(ll p){
if (p==1||!(p&1)) return p==2;
ll q=p-1,c=0;
while (q&1) q>>=1,c++;
for(int t=1;t<=4;t++){
ll x=rd()%(p-1)+1;
if (ksm(x,p-1,p)!=1) return 0;
x=ksm(x,q,p);
if (x==p-1||x==1) continue;
int k=0;
while (k<=c&&x!=p-1) k++,x=mul(x,x,p);
if (k>c) return 0;
}
return 1;
}
ll p[maxc]; int tot,c[maxc];
void getd(ll P){
if (P==1) return;
if (mr(P)) {
for(int i=1;i<=tot;i++) if (p[i]==P) {c[i]++;return;}
tot++,p[tot]=P,c[tot]=1;
return;
}
while (1){
ll c=rd()%(P-1)+1,t1=rd()%(P-1)+1,t2=(mul(t1,t1,P-1)+c)%(P-1)+1,g=1;
int cnt=0;
while (t1!=t2){
ll t=abs(t2-t1);
g=mul(g,t,P);
if (!g){
ll d=gcd(t,P);
getd(d),getd(P/d);
return;
}
if (++cnt==127){
cnt=0;
ll d=gcd(g,P);
if (d>1) {getd(d),getd(P/d);return;}
}
t1=(mul(t1,t1,P-1)+c)%(P-1)+1;
t2=(mul(t2,t2,P-1)+c)%(P-1)+1;
t2=(mul(t2,t2,P-1)+c)%(P-1)+1;
}
ll d=gcd(g,P);
if (d>1) {getd(d),getd(P/d);return;}
}
}
int mp[maxc]; ll f[maxf];
void add(ll x){
ll m;
if (x==1) m=1; else {
m=P-1;
for(int i=1;i<=tot;i++){
for(int j=1;j<=c[i];j++)
if (ksm(x,m/p[i],P)!=1) break;
else m/=p[i];
}
}
int s=0; ll tmp=m;
for(int i=1;i<=tot;i++)
while (tmp%p[i]==0) s+=mp[i-1],tmp/=p[i];
(f[s]+=m)%=P;
}
void cover(){
for(int i=1;i<=tot;i++)
for(int s=mp[tot]-1;s>=0;s--) if (s%mp[i]/mp[i-1]>0)
(f[s-mp[i-1]]+=f[s])%=P;
for(int s=0;s<mp[tot];s++) f[s]=mul(f[s],f[s],P);
for(int i=1;i<=tot;i++)
for(int s=0;s<mp[tot]-1;s++) if (s%mp[i]/mp[i-1]<c[i])
(f[s]+=P-f[s+mp[i-1]])%=P;
}
void getans(){
ll ans=0;
for(int s=0;s<mp[tot];s++){
ll d=1;
for(int i=1;i<=tot;i++)
for(int j=1;j<=s%mp[i]/mp[i-1];j++)
d=d*p[i];
(ans+=mul(f[s],ksm(mul(d,d,P),P-2,P),P))%=P;
}
printf("%lld\n",ans);
}
int main(){
freopen("wlwl.in","r",stdin);
freopen("wlwl.out","w",stdout);
scanf("%d%lld",&n,&P),sd=19260817114514ll;
getd(P-1);
for(mp[0]=1,i=1;i<=tot;i++) mp[i]=mp[i-1]*(c[i]+1);
for(i=1;i<=n;i++){
ll x; scanf("%lld",&x);
add(x);
}
cover();
getans();
}