http://acm.hdu.edu.cn/showproblem.php?pid=4910
题目描述:对给定的n,求
[1,n]
中与n互质的数的乘积%n
数据范围:
n<=1018
即计算n的缩系元素之积%n,必然也在缩系之中。
当n为素数是 答案为n-1
经打表发现答案为1 ,n-1
现在我们来证明一下 = =
考虑缩系元素i,j(i,j,可以相等) 必然有
i∗j
证明:
i∗j+k∗n=1
根据扩展欧几里得原理得
j∈[1,n−1]
又因为
i∗j
若j不为缩系元素,矛盾 = =
若 i≠j 就不需要考虑他们了
若
i=j
则
gcd(a,n)=gcd(n−a,a)=1
;(令a=i=j)
而
(n−a)≡−a
(mod n)
a∗(n−a)≡an−a∗a≡−a∗a
(mod n)
已知
a∗a≡1
(mod n)则
−a∗a≡−1
(mod n)
当
n=2
时,
a=1
当
n≠2
时,
n−a
与a成对出现。若这样的对数为奇数时,答案为-1,反之为1
接下来将
a∗a≡1
(mod n)变形得
(a+1)(a−1)≡0
(mod n)
将n质因数分解为
n=pk00∗pk11∗pk22…∗pkii
根据中国剩余定理转化为若干个同余方程
(a+1)(a−1)≡0
(mod
pkii
)
而每个方程对应一组解
先考虑单个方程 若
pi>2
则
a≡1,pkii−1
(mod n)//不意味着只有2个解
若pi=2 当ki=1是 a=1 1个解;当ki=2时 a=1,3 2个解;当ki>2时,
a≡−1,+1
(mod
2ki
)
终上分析得
当
n=4,pk,2∗pk
时 答案为n-1 (其中p为质数,k为自然数)
由于数据范围大,在判断素数时,要用Miller_Rabin算法(利用费马小定理判断,但有伪素数的存在,所以是一个概率计算)
这道题很难,当初卡了我很久…
蒟蒻加油 ↖(^ω^)↗
#include<iostream>
#include<cstdio>
#include<ctime>
#include<algorithm>
#include<cmath>
#define LL long long int
using namespace std;
LL n,pos,ans;
int prime[1000010];
bool flag[1000010];
void init()
{
pos=0;
for(int i=2;i<=1e6;++i)
{
if(!flag[i])
prime[++pos]=i;
for(int j=1;j<=pos;++i)
{
if(i*prime[j]>1e6)break;
flag[i*prime[j]]=1;
if(i%prime[j]==0)break;
}
}
}
LL mul(LL a,LL b,LL p)
{
LL ans=0;
while(b>0)
{
if(b&1)
{
ans+=a;
if(ans>=p)ans-=p;
}
a+=a;
if(a>=p)a-=p;
b>>=1;
}
return ans;
}
LL power(LL a,LL m,LL temp)
{
LL ans=1;
while(m>0)
{
if(m&1)
ans=mul(ans,a,temp);
a=mul(a,a,temp);
m>>=1;
}
return ans;
}
bool Miller_Rabin(LL n)
{
if(n==2||n==3)return 1;
if(n<2||!(n&1))return 0;
LL a,code=0,k=n-1,ans,t;
while(!(k&1))
{
k>>=1;
++code;
}
for(int i=1;i<21;++i)
{
a=rand()%(n-1)+1;
ans=power(a,k,n);
t=ans;
for(int j=0;j<code;++j)
{
ans=mul(ans,ans,n);
if(ans==1&&t!=1&&t!=n-1)
return 0;
t=ans;
}
if(ans!=1)
return 0;
}
return 1;
}
bool judge(LL n)
{
for(int i=1;i<=pos;++i)
{
if(n%prime[i]==0)
{
do{n/=prime[i];}
while(n%prime[i]==0);
if(n==1)
return 1;
return 0;
}
}
return 0;
}
int main()
{
srand(time(NULL));
init();
while(scanf("%I64d",&n)!=EOF&&n!=-1)
{
if(n==1){printf("0\n");continue;}
if(n==4){printf("3\n");continue;}
if(n%4==0){printf("1\n");continue;}
//将n分解分所有质因子相乘,质因子2个数为a,其余质因子个数为b,ans=(a==0?a:a-1)+b;当ans<2时结果为n-1,否则结果为1.
ans=0;
LL k=n;
while(!(n&1))
{
n>>=1;
++ans;
}
if(ans>0)--ans;
if(n!=1)
{
if(Miller_Rabin(n))
++ans;
else
{
LL i=(LL)sqrt(n+0.5);
if(i*i==n&&Miller_Rabin(i)||judge(n))//判断k是否能写成a^p
++ans;
else ans+=2;//否则最少是两个质因子
}
}
if(ans<2)
printf("%I64d\n",k-1);
else printf("1\n");
}
return 0;
}