Hướng dẫn giải của Số học 1


Chỉ dùng lời giải này khi không có ý tưởng, và đừng copy-paste code từ lời giải này. Hãy tôn trọng người ra đề và người viết lời giải.
Nộp một lời giải chính thức trước khi tự giải là một hành động có thể bị ban.

Lưu ý: Các code mẫu dưới đây chỉ mang tính tham khảo và có thể không AC được bài tập này

Code mẫu của RR

//Written by Nguyen Thanh Trung
//Tai lieu tham khao: Sqrt Mod P - Ngo Minh Duc
//Shanks-Tonelli's algorithm
{$R+,Q+}
{$Mode objFPC}
uses math;
const
  FINP='';
  FOUT='';
var
  x,a,p:longint;
  test:longint;
  f1,f2:text;
procedure openF;
begin
  assign(f1,FINP); reset(f1);
  assign(f2,FOUT); rewrite(f2);
end;
procedure closeF;
begin
  close(f1); close(f2);
end;
function Legrende(a,n:longint):int64; //The only function that I don't understand :(
var
  e,s:int64;
begin
  if a<=1 then Legrende:=a
  else
    begin
      e:=0;
      while a and 1=0 do
        begin
          inc(e);
          a:=a>>1;
        end;
      if e and %1=0 then s:=1
      else if (n and %111=1) or (n and %111=7) then s:=1
      else if (n and %111=5) or (n and %111=3) then s:=-1;
      if (n and %11=3) and (a and %11=3) then s:=-s;
      if a=1 then Legrende:=s else Legrende:=s*Legrende(n mod a,a);
    end;
end;
function lt(a,k:longint):longint; //Tinh a^k (mod p)
var
  temp:longint;
begin
  if k and %1=0 then temp:=1 else temp:=a;
  k:=k>>1;
  while (k>0) do
    begin
      a:=(int64(a)*a) mod p;
      if k and %1=1 then temp:=(int64(a)*temp) mod p;
      k:=k>>1;
    end;
  exit(temp);
end;
function ord(b:longint):longint;
var
  kq:longint;
begin
  kq:=0;
  while b<>1 do
    begin
      b:=(int64(b)*b) mod p;
      inc(kq);
    end;
  exit(kq);
end;
procedure solve;
var
  c,z,m,k,kk,b,x,xx:longint;
begin
  if Legrende(a,p)=-1 then begin writeln(f2,'Khong co'); exit; end;
  //Dat p-1=2^k*m (m le)
  m:=p-1; k:=0;
  while m and %1=0 do
    begin
      k+=1;
      m:=m>>1;
    end;
  //Chon x=2^((m+1)/2)
  x:=lt(a,(m+1)>>1);
  b:=lt(a,m);
  if b=1 then
    begin
      xx:=-x+p;
      if x<xx then writeln(f2,x,' ',xx)
      else writeln(f2,xx,' ',x);
      exit;
    end;
  //Chon z ngau nhien sao cho z la non-residue
  repeat
    z:=random(p-1)+1;
  until Legrende(z,p)=-1;
  c:=lt(z,m);
  repeat
    kk:=ord(b);
    x:=(lt(c,1<<(k-kk-1))*x) mod p;
    b:=(lt(c,1<<(k-kk))*b) mod p;
  until b=1;
  xx:=-x+p;
  if x<xx then writeln(f2,x,' ',xx)
  else writeln(f2,xx,' ',x);
end;
begin
  openF;
  read(f1,test);
  for test:=1 to test do
    begin
      read(f1,a,p); a:=a mod p;
      if p=2 then
        begin
          if a=1 then writeln(f2,1) //Xet rieng TH p=2
          else writeln(f2,'Khong co');
        end
      else solve; //Shanks-Tonelli's algorithm
    end;
  closeF;
end.

Code mẫu của hieult

#include <cstdio>
//#include <conio.h>
typedef long long ll;

ll a,n,mu2[50];

long long mu(ll u,ll k)
{
      if(k==1)
          return u;
      else
      {
          ll t = mu(u,k/2);
          if(k%2==0)
               return (t*t)%n;
          else return (t*t*u)%n;
      }
}

ll xuly(ll a,ll p)
{
     if(a%n==0)
         return 0;
     if(mu(a,(p-1)/2)!=1)
         return -1;
     ll m = p-1,k=0,z,c,kk,the;
     while(m%2==0){k++;m/=2;}
     ll x = mu(a,(m+1)/2), b = mu(a,m);
     if(b==1) return x;
     the = b;
     for(z=2;;z++) {if(mu(z,(p-1)/2)==p-1) break;}
     c = mu(z,m);
     while(b!=1)
     {
          the = b,kk=0;
          while(the!=1) {kk++; the=(the*the)%p;}
          x = (mu(c,mu2[k-kk-1])*x)%p;
          b = (mu(c,mu2[k-kk])*b)%p;          
     }
     return x;
}

int main()
{
    mu2[0] = 1; for(int i = 1;i<=40;i++) mu2[i] = mu2[i-1]*2;
    int test;
    scanf("%d",&test);
    for(int itest=0;itest<test;itest++){
            scanf("%lld %lld",&a,&n);
            a = a%n;
            if(a%n==0)
                  printf("0\n");
            else if(n==2)
                printf("1\n");
            else
            {
                long long x = xuly(a,n);
                long long y = n-x;
                if(x==-1)
                     printf("Khong co\n");
                else 
                {
                     if(x>y)
                     {
                            long long temp = x;
                            x = y;
                            y = temp;
                     }
                     printf("%lld %lld\n",x,y);
                }
            }
    }
   // getch();
}

Code mẫu của ll931110

//#pragma comment(linker, "/STACK:16777216")
#include <algorithm>
#include <bitset>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <deque>
#include <fstream>
#include <functional>
#include <iostream>
#include <map>
#include <set>
#include <sstream>
#include <stack>
#include <queue>
#include <vector>
#include <utility>
using namespace std;

int a,p,T;

int gen(int x)
{
    double slope = 1.0 * rand()/RAND_MAX;
    return (int) trunc(slope * x);
}

int power(int x,int v)
{
    if (!v) return 1;
    int q = power(x,v/2);
    q = (q * q) % p;
    if (v & 1) q = (q * x) % p;
    return q;
}

int Legrende(int x)
{
    return power(x,(p - 1)/2);
}

int main()
{
//    freopen("root.in","r",stdin);
//    freopen("root.ou","w",stdout);
    scanf("%d", &T);
    srand(time(NULL));
    while (T--)
    {
        scanf("%d %d", &a, &p);
        if (p == 2)
        {
            printf("1\n");  continue;
        }
        if (Legrende(a) == p - 1)
        {
            printf("Khong co\n");  continue;
        }
        int b;
        while (1)
        {
            b = gen(p);  
            if (!b) continue;
            if (Legrende(b) == p - 1) break;
        }

        int s = 0,t = p - 1;
        while ( (t & 1) == 0)
        {
            t >>= 1;  s++;
        }

        int r = power(a,(t + 1)/2),c = power(b,t),inv = power(a,p - 2);
        for (int i = 1; i < s; i++)
        {
            int d = (((r * r) % p) * inv) % p; 
            d = power(d,1 << (s - i - 1));
            if (d == p - 1) r = (r * c) % p;
            c = (c * c) % p;
        }
        int p1 = r,p2 = p - r;
        if (p1 > p2) swap(p1,p2);
        printf("%d %d\n", p1, p2);
    }
}

Code mẫu của khuc_tuan

#include "stdio.h"
#include "algorithm"

using namespace std;

#define FI first
#define SE second

typedef int kint;

#define int long long

typedef pair<int,int> PII;

int gcd(int a,int b) {
    while(a!=0 && b!=0) {
        if(a<b) b%=a;
        else a%=b;
    }
    return a+b;
}

PII Exgcd(int a,int b) {
    if(a==1) return PII(b+1,-1);
    if(b==1) return PII(-1,a+1);
    bool d=false;
    if(a>b) a^=b, b^=a, a^=b, d=true;
    PII r = Exgcd(a,b%a);
    int t = r.FI/b;
    r.FI -= t*b;
    r.SE += t*a;
    if(!d) return PII(r.FI-r.SE*(b-b%a)/a,r.SE);
    else return PII(r.SE, r.FI-r.SE*(b-b%a)/a);
}

int Jacobi(int a,int n) {
    //printf("%I64d %I64d", a, n);
    if(a==0) return 0;
    if(a==1) return 1;
    int e=0, a1=a, s, n1;
    while(a1%2==0) { a1/=2; ++e; }
    if(e%2==0 || n%8==1 || n%8==7) s=1;
    else s=-1;
    if(n%4==3 and a1%4==3) s=-s;
    n1 = n % a1;
    if(a1==1) return s;
    else return s * Jacobi(n1, a1);
}

int tinhdu(int cs, int mu, int mod) {
    if(mu==0) return 1;
    if(mu==1) return cs%mod;
    int t = tinhdu(cs, mu/2, mod);
    if(mu%2==0) return t*t%mod;
    else return t*t%mod*cs%mod;
}

kint main() {
    int st, a, p, b, s, t, a_1, c, r;
    scanf("%lld",&st);
    while(st--) {
        scanf("%lld%lld", &a, &p);
        a %= p;
        if(p==2) {
            printf("1\n");
        }
        else if(Jacobi(a,p)==-1) {
            printf("Khong co\n");
        }
        else {
            if(p%4==3) {
                r = tinhdu(a, (p+1)/4, p);
            }
            else if(p%8==5) {
                int d = tinhdu(a, (p-1)/4, p);
                if(d==1) r = tinhdu(a, (p+3)/8, p);
                else r = 2 * a * tinhdu(4*a%p, (p-5)/8, p) % p;
            }
            else {
                do {
                    b = rand()%(p-1) + 1;
                } while(Jacobi(b,p)!=-1);
                //printf("ok %lld ", b);
                t = p-1;
                s = 0;
                while(t%2==0) { t/=2; ++s; }
                a_1 = Exgcd(a,p).FI;
                //printf("asdasd %lld %lld",a_1, Exgcd(a,p).SE);
                a_1 %= p;
                if(a_1<0) a_1+=p;
                c = tinhdu(b, t, p);
                r = tinhdu(a, (t+1)/2, p);
                int mm = 1;
                for(int i=0;i<s-2;++i) mm*=2;
                for(int i=1;i<=s-1;++i) {
                    int d = tinhdu(r*r*a_1 % p, mm, p);
                    if(d == p-1 || d==-1) r = r*c % p;
                    c = c*c%p;
                    mm /= 2;
                }
            }       
            if(r*r%p != a) printf("Sai\n");
            if(r<p-r) printf("%lld %lld\n", r, p-r);
            else printf("%lld %lld\n", p-r, r);
        }
    }
    return 0;
}

Bình luận

Hãy đọc nội quy trước khi bình luận.


Không có bình luận tại thời điểm này.