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;
}

浙公网安备 33010602011771号