T661179 8.27考试t1

题目链接:

https://www.luogu.com.cn/problem/T661179

题目描述

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

暴力求解?

考试的时候首先想到的是暴力枚举x的次幂,一直到第二次出现1就说明进入了循坏(第一次即x^0=1),代码如下:

#include<bits/stdc++.h>
using namespace std;
int main(){
	int t,p,x;
	cin>>t;
	for(int i=1;i<=t;i++){
		cin>>p>>x;
		int ans=1,m;
		m=x;//每上升一次幂就是在前一次幂的基础上在乘一个x,考虑后续x的值会变所以先记录下来 
		x=x%p;
		if(x==1){
			cout<<ans<<endl;
			continue;
		}
		ans++;//i等于1时特殊处理 
		while(1){
			x=(x*m)%p;//边乘边取余,不然会爆(我是不会告诉你我因为这个原因考场爆零的
			if(x==1) break;
			ans++;
		}
		cout<<ans<<endl;
	}
	return 0;
}

由于50%的数据p<=1e4,所以这段代码能得50分;

正解

如何优化?再次读题容易发现x属于p的缩减剩余集这个条件是没有在暴力做法中用上的;重新整理暴力做法的思路,其实就是求一个除0外最小的n,使得:

\(x^n\equiv1\bmod p\)

由于x和p互质,很容易想到欧拉定理(别问我考试咋没想到):

\(a^{\varphi(P)}\equiv1\bmod p (gcd(a,p)=1)\)

根据欧拉定理可知n=\(\varphi(P)\)时一定循环到1,所以最小的n一定是\(\varphi(P)\)或是其因子,依次枚举即可
正解代码如下:

#include<bits/stdc++.h>
#define ll long long//貌似其实可以不开long long
using namespace std;
ll t,p,x,y[10005],tot;
ll oula(ll n){//求欧拉函数
	ll s=n;
	for(int i=2;i*i<=n;i++){
		if(n%i==0){
			s-=s/i;
			while(n%i==0) n/=i;
		}
	}
	if(n>1) s-=s/n;
	return s;
}
ll quai(ll x,ll y,ll mod){//快速幂
	ll m=1;
	ll n=x;
	while(y>0){
		if(y&1){
			m=m*n;
			m=m%mod;
		}
		n=n*n;
		n=n%mod;
		y>>=1;
	}
	return m;
}
void qiuyinzi(int x){求因子
	for(int i=1;i*i<=x;i++){
		if(x%i==0){
			y[tot++]=i;
			y[tot++]=x/i;//i是因子所以x/i一定也是因子
		}
	}
	sort(y,y+tot);//由于不是从小到大加入的,所以排一下序
}
int main(){
	cin>>t;
	for(int i=1;i<=t;i++){
		tot=1;
		cin>>p>>x;
		ll n,a;
		a=oula(p);
		qiuyinzi(a);
		for(int j=1;j<=tot;j++){
			int n=quai(x,y[j],p);
			if(n==1){
				cout<<y[j]<<endl;
				break;
			}
		}
	}
	return 0;
}
posted @ 2025-08-27 20:54  Turkey_VII  阅读(19)  评论(3)    收藏  举报