数论练习1题解B

数论练习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;
 }
}

就这样了 好久不写了 也不知说啥 新的第一篇就这样吧。

猜你喜欢

转载自blog.csdn.net/hollyidyllic/article/details/84708046