G
N
I
D
A
O
L

【题解】P6730 [WC2020] 猜数游戏

本题的前置是弱化版的 P5605 小 A 与两位神仙

要求所有询问集合大小之和,考虑拆贡献,变成每个数出现在多少个子集的询问集合中。

先刻画什么时候一个数 \(a\) 会被放进询问集合,容易观察到的一点是,不存在另一个 \(b\) 使得 \(b\) 的某个幂次与 \(a\) 同余。(此时先询问 \(b\) 以后 \(a\) 会被报出来,包括 \(a\) 的幂次也会被报出来),而且若不存在这样的 \(b\) ,则 \(a\) 一定需要询问自己本身,故该条件是充要的。

推导一下 \(\exist m,\ s.t.\ b^m\equiv a\pmod p\) 的等价形式,这其实是 P5605 的内容,放在这里再写一下。

显然 \(a,b\) 要么都与 \(p\) 互质,要么都不与 \(p\) 互质

先考虑 \(a,b\) 均与 \(p\) 互质的情况

因为 \(p\) 是素数或奇素数幂,则由原根存在定理知 \(p\) 存在原根 \(g\)

\(b=g^y,a=g^x\) ,有 \(g^{ym}\equiv g^x\pmod p\) ,故 \(ym\equiv x\pmod {\varphi(p)}\)

这个式子可以看成二元一次不定方程,\(m\) 有解 \(\iff\) \(\gcd(y,\varphi(p))|x\)

由于 \(\gcd(y,\varphi(p))|\varphi(p)\) ,故上式等价于 \(\gcd(y,\varphi(p))|\gcd(x,\varphi(p))\)

因为 \(\delta_p(g^y)=\displaystyle\frac{\delta_p(g)}{\gcd(\delta_p(g),y)}\),而 \(\delta_p(g)=\varphi(p)\)

\(\gcd(y,\varphi(p))=\gcd(\delta_p(g),y)=\displaystyle\frac{\delta_p(g)}{\delta_p(g^y)}\)

因此只需 \(\displaystyle\frac{\delta_p(g)}{\delta_p(g^y)}\mid\frac{\delta_p(g)}{\delta_p(g^x)}\), 即 \(\delta_p(a)\mid\delta_p(b)\),求出每个数的阶只需对 \(\varphi(p)\) 的因数判断即可

再考虑 \(a,b\) 均不与 \(p\) 互质的情况

\(p\) 的质因子为 \(q\)\(q\) 可以为 \(p\) 本身),则 \(q\mid a\)\(q\mid b\)

\(b\) 的若干幂次以后必为 \(p\) 的倍数,只需暴力枚举 \(m\) ,时间复杂度 \(O(\log p)\)

到这里基本上已经结束了,只需要将所有数按照是否与 \(p\) 互质分成两大类,两类中对每个数 \(x\) 分别统计有多少数可以经过乘幂到达自己,记为 \(cnt_x\)。因此若 \(x\) 在询问集合中,则原集合中必没有这 \(cnt_x\) 个数,剩下的数在不在原集合无所谓,贡献为 \(2^{cnt_x}\)。但注意到 阶相等的多个数之间形成强连通分量,对它们钦定一个顺序即可。另一种解决方法是对所有阶进行枚举,每个阶中至少出现一个数,故再乘上 \(2^k-1\) 即可,其中 \(k\) 为 阶是当前枚举值的数的个数。

代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=5009;
const ll MOD=998244353;
ll n,p,q,phi,nD,d[N],pw2[N];
ll cnt[N],ans;
vector<ll> vec;
map<ll,ll> mp,id;

inline ll qpow(ll a,ll b,ll MOD){
	ll res=1;
	while(b){
		if(b&1) res=(res*a)%MOD;
		a=(a*a)%MOD;
		b>>=1;
	}
	return res;
}
inline ll get(ll x){
	ll res=phi;
	for(ll i=1;i<=nD;i++){
		while(res%d[i]==0&&qpow(x,res/d[i],p)==1){
			res/=d[i];
		}
	}
	return res;
}
void init(){
	pw2[0]=1;
	for(ll i=1;i<=n;i++) pw2[i]=pw2[i-1]*2%MOD;
	for(ll i=2;i*i<=p;i++){
		if(p%i==0){
			q=i;
			break;
		}
	}
	if(q==0) q=p;
	phi=p-p/q;
	ll x=phi;
	for(ll i=2;i*i<=x;i++){
		if(x%i==0){
			d[++nD]=i;
			while(x%i==0){
				x/=i;
			}
		}
	}
	if(x>1) d[++nD]=x;
}
int main(){
	ios::sync_with_stdio(false);
	cin>>n>>p;
	init();
	for(ll i=1;i<=n;i++){
		ll a; cin>>a;
		if(a%q==0){
			id[a]=vec.size();
			vec.push_back(a);
		}
		else{
			ll ord=get(a);
			mp[ord]++;
		}
	}
	
	fill(cnt,cnt+vec.size(),n);
	for(ll i=0;i<vec.size();i++){
		ll u=vec[i];
		for(ll v=u;v;v=v*u%p){
			if(id.count(v)){
				cnt[id[v]]--;
			}
		}
	}
	for(ll i=0;i<vec.size();i++){
		ans+=pw2[cnt[i]];
	}
	for(auto u:mp){
		ll res=n;
		for(auto v:mp){
			if(v.first%u.first==0){
				res-=v.second;
			}
		}
		ans+=pw2[res]*(pw2[u.second]-1)%MOD;
	}
	printf("%lld\n",ans%MOD);
	return 0;
}
posted @ 2025-06-26 11:44  QWQcoding  阅读(16)  评论(0)    收藏  举报