2025/8/27 数论部分测试

T1

Question

给你一个数\(p\),缩减剩余系是指由\([1,p]\)之间的与\(p\)互质的整数组成的集合。现在给你一个数\(x\),求在模\(p\)意义下\(x\)的幂集有多少个不同的值,(形如1,\(x\)\(x^2\)\(x^3\),...的数叫做\(x\)的幂集)

Sol

显然\(x^n\)会周期性变化,所以转化为求最小的\(n\)满足\(x^n\equiv1 \bmod p\)。根据欧拉定理,最小的\(n\)\(\varphi(n)\)的因数,即\(n_{min}\mid\varphi(n)\)。枚举因数快速幂判断即可。
时间复杂度大约为\(\mathcal{O}(T\log\varphi(n)\sqrt{\varphi(n)})\)

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
ll phi(ll n){
	ll ans=n;
	for(ll i=2;i*i<=n;i++){
		if(n%i==0){
			ans=ans/i*(i-1);
		}
		while(n%i==0)n/=i;
	}
	if(n>1)ans=ans/n*(n-1);
	return ans;
}
ll qp(ll a,ll n,ll p){
	ll ans=1;
	while(n){
		if(n&1)ans=(ans*a)%p;
		n>>=1;
		a=(a*a)%p;
	}
	return ans;
}
signed main(){
	int T;
	scanf("%d",&T);
	while(T--){
		int p,x;
		scanf("%d%d",&p,&x);
		int k=phi(p);
        vector<ll>vc;
        vc.clear();
		for(int i=1;i*i<=p;i++){
            if(k%i)continue ;
            vc.push_back(i);
            if(i*i^p)vc.push_back(k/i);
        }
        sort(vc.begin(),vc.end());
        for(auto i:vc){
            if(qp(x,i,p)==1){
                printf("%d\n",i);
                break;
            }
        }
	}
	return 0;
}

T2

Question

有一个按照以下规则生成的无限集

规则一:\(1\)在集合中

规则二:若\(x\)在集合中,那么\(a* x\)以及\(b+x\)在集合中

每次询问数\(n\)是否在集合中

Sol

首先特判,当\(n=1\)\(b=1\)显然Yes,当\(a=1\)时判断\((n-1)\bmod b\)是否为\(0\)

然后思考,其实如果\(n\)在集合内,\(n\)可以表示为\(a^x+b(···)\)的形式,所以只需要枚举\(a\)的次幂即可。

注意开\(long\) \(long\)

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
signed main(){
	ll T;
	cin>>T;
	while(T--){
		ll n,a,b;
		cin>>n>>a>>b;
		if(n==1){
			cout<<"Yes\n";
			continue;
		}else if(a==1){
			if((n-1)%b==0){
				cout<<"Yes\n";
				continue;
			}else{
				cout<<"No\n";
				continue;
			}
		}else if(b==1){
			cout<<"Yes\n";
			continue;
		} 
		ll pw=1;
		bool flg=0;
		while(pw<=n){
			if((n-pw)%b==0){
				flg=1;
				break; 
			}
			pw*=a;
		}
		if(flg)cout<<"Yes\n";
		else cout<<"No\n";
	}
	return 0;
}

T3

T4

Question

求在\([1,x]\)中有多少\(n\),满足:\(n∗a^n\equiv b\bmod p\)。保证\(p\)\(a\)互质。

Sol

注意到\(n \bmod p\)\(p\)为循环,\(a^n\bmod p\)\(\varphi(p)\)为循环,所以先求他两个的\(lcm\),因为涉及除法所以用到了逆元,因为\(p\)不一定为质数所以用\(exgcd\)
对于每个可能的余数\(i\)(从\(1 \to \varphi(p)\)遍历),求解以下方程组:
\(\begin{align}n \equiv i \pmod{\varphi(p)}\\ n \equiv b\cdot a^{-i} \pmod{p}\end{align}\)
对其进行\(exCRT\)即可。注意判断最小解是否在\([1,x]\)中。

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
inline ll phi(ll n){
	ll ans=n;
	for(ll i=2;i*i<=n;i++){
		if(n%i==0){
			ans=ans/i*(i-1);
		}
		while(n%i==0)n/=i;
	}
	if(n>1)ans=ans/n*(n-1);
	return ans;
}
inline ll exgcd(ll a,ll b,ll &x,ll &y){
    if(!b){
        x=1;y=0;return a;
    }
    ll x0,y0,t;
    t=exgcd(b,a%b,x0,y0);
    x=y0;
    y=x0-(a/b)*y0;
    return t;
}
inline ll inv(ll a,ll p){
    ll g,x,y;
    g=exgcd(a,p,x,y);
    if(g!=1)return -1;
    return(x%p+p)%p;
}
signed main(){
	ll a,b,p,x,k1,k2;
    scanf("%lld%lld%lld%lld",&a,&b,&p,&x);
    ll base=b,na=inv(a,p);
    ll ph=phi(p),gcd=exgcd(p,ph,k1,k2);
    ll lcm=p/gcd*ph;
    ll ans=0;
    for(register ll i=1;i<=ph;i++){
        base=base*na%p;
        ll nw=i-base;
        if(nw%gcd)continue;
        long long nn=(base+(nw/gcd)*p%lcm*k1%lcm+lcm)%lcm;
        ans+=(x/lcm)+((x%lcm)>=nn);
    }
    cout<<ans;
	return 0;
}
posted @ 2025-08-28 10:46  nick_zha  阅读(27)  评论(2)    收藏  举报