JZOJ6782.【NOI2020.08.06模拟】wlwl

Description

JZOJ6782.【NOI2020.08.06模拟】wlwl_第1张图片

  • n ≤ 1 e 5 , p ≤ 1 e 18 n\le1e5,p\le1e18 n1e5,p1e18

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 gxord(a)=1,所以 ( p − 1 ) ∣ x ∗ o r d ( a ) (p-1)|x*ord(a) (p1)xord(a),把 x x x除到左边,可以得到 p − 1 ( x , p − 1 ) ∣ o r d ( a ) \frac{p-1}{(x,p-1)}|ord(a) (x,p1)p1ord(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,p1)p1
  • 接下来我们考虑 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(%(p1)),同理 ( y , p − 1 ) ∣ x i (y,p-1)|xi (y,p1)xi,所以 i = ( y , p − 1 ) ( x , y , p − 1 ) i=\frac{(y,p-1)}{(x,y,p-1)} i=(x,y,p1)(y,p1)最小。
  • ( x , p − 1 ) = p − 1 o r d ( a ) (x,p-1)=\frac{p-1}{ord(a)} (x,p1)=ord(a)p1 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)p1,ord(b)p1)ord(b)p1=lcm(ord(a),ord(b))p1ord(b)p1=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} iminjmin=(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)),dp1,就可以直接计算答案。
  • o r d ( a ) ord(a) ord(a)可以直接试除法找到一个最小的 a i = 1 , i ∣ p − 1 a^{i}=1,i|p-1 ai=1ip1,每一次枚举 p − 1 p-1 p1的一个质因子即可,做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();
}

你可能感兴趣的:(题解,数论,数论,同余,高维后缀和,原根)