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  阅读(40)  评论(0)    收藏  举报