数论练习1题解B
新号,新开始。第一篇题解。
先上题目(HDU1395)
这道题目上来就没有数据范围(捂住额头真的合适嘛)
然后就是一句话 暴力能过(那你给个数据范围能怎么样嘛)
暴力的思路也就是运用同余性质用循环不断尝试2^i直到满足条件,每次乘2求余,直到余数为1
**#include<iostream>
using namespace std;
int main()
{
long long i,t,n;
while(cin>>n)
{
t=1;
if (n==1||n%2==0) cout<<0<<endl;
else
{
t=t*2;
for (i=2;i<=n-1;i++)
if (t!=1) t=(t*2)%n; else break;
cout<<i-1<<endl;
}
}
return 0;
}
但暴力过明显**不优雅(因为平常练习 总要多思考一下)
由数论我们可以知道几个结论(证明此处略)
1:我们用φ(n)表示满足条件的最小2^k
2:对于n=(p1^k1)
(p2^k2)…
(pn^kn)
我们有φ(n)=[φ(p1^k1),…](即最小公倍数)(此易证)
3:对于φ(p1^k1) 我们可以由数学归纳法得到
它等于φ(p1)*p1^(k1-1)
然后就可以简化一些 但是对于大素数 当时并没有发现好的处理方法
然后贴代码 如下
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int pd[100001];
int gcd(int,int);
int main()
{
int i,j,t,tn,num,n;
memset(pd,0,sizeof(pd));
pd[1]=1;
for (i=2;i<=50000;i++)
{
if (pd[i]==0)
{
tn=2;
for (j=1;j<i;j++)
if (tn==1) break;else tn=(tn*2)%i;
pd[i]=j;
for (j=2;j<=50000/i;j++)
pd[i*j]=1;
}
}
while (cin>>n)
{
if (n%2==0||n==1) cout<<"2^? mod "<<n<<" = 1"<<endl;
else
{
if (pd[n]!=1) cout<<"2^"<<pd[n]<<" mod "<<n<<" = 1"<<endl;
else
{
t=0;
for (i=3;i<=n/2;i++)
if (pd[i]!=1&&n%i==0)
{
tn=n;
num=0;
while (tn%i==0)
{
num++;
tn=tn/i;
}
tn=pd[i];
for (j=2;j<=num;j++)
tn=tn*i;
t=gcd(t,tn);
}
cout<<"2^"<<t<<" mod "<<n<<" = 1"<<endl;
}
}
}
return 0;
}
int gcd(int a,int b)
{
if (a==0) return b;
else
{
int temp,ta,tb;
ta=a;
tb=b;
if (a<b)
{
temp=a;
a=b;
b=temp;
}
while (b!=0)
{
temp=a%b;
a=b;
b=temp;
}
return ta*tb/a;
}
}
就这样了 好久不写了 也不知说啥 新的第一篇就这样吧。