Tính toán nghịch đảo của một số nguyên modulo 100000000003


21

Nhiệm vụ là như sau. Cho một số nguyên x(sao cho xmodulo 100000000003không bằng 0) được trình bày cho mã của bạn theo bất kỳ cách nào bạn thấy thuận tiện, hãy xuất một số nguyên khác y < 100000000003sao cho (x * y) mod 100000000003 = 1.

Mã của bạn phải mất ít hơn 30 phút để chạy trên máy tính để bàn tiêu chuẩn cho bất kỳ đầu vào nàox như vậy |x| < 2^40.

Các trường hợp thử nghiệm

Đầu vào: 400000001. Đầu ra: 65991902837

Đầu vào: 4000000001. Đầu ra: 68181818185

Đầu vào: 2. Đầu ra: 50000000002

Đầu vào: 50000000002. Đầu ra: 2.

Đầu vào: 1000000. Đầu ra: 33333300001

Hạn chế

Bạn không được sử dụng bất kỳ thư viện hoặc hàm dựng sẵn nào thực hiện số học modulo (hoặc thao tác nghịch đảo này). Điều này có nghĩa là bạn thậm chí không thể làm a % bmà không thực hiện %chính mình. Tuy nhiên, bạn có thể sử dụng tất cả các hàm dựng sẵn số học không modulo khác.

Câu hỏi tương tự

Điều này tương tự với câu hỏi này mặc dù hy vọng đủ khác biệt để vẫn được quan tâm.


Vậy a- (a / b) * b có ổn không?
dùng253751

@immibis Điều đó có vẻ tốt.

tag: mã bị hạn chế?
Felipe Nardi Batista

1
Có gì đặc biệt 100000000003? (chỉ thắc mắc)
NoOneIsHãy

1
@Lembik Trong trường hợp đó, bạn có thể đề cập đến yêu cầu đó y <100000000003 trong câu hỏi không?
isaacg

Câu trả lời:


16

Bình thường, 24 byte

L-b*/bJ+3^T11Jy*uy^GT11Q

Bộ kiểm tra

Điều này sử dụng thực tế là một ^ (p-2) mod p = a ^ -1 mod p.

Đầu tiên, tôi tự thực hiện lại mô-đun, đối với trường hợp cụ thể của mod 100000000003. Tôi sử dụng công thức a mod b = a - (a/b)*b, trong đó /phân chia nổi. Tôi tạo mô-đun với 10^11 + 3, sử dụng mã +3^T11, sau đó lưu nó vào J, sau đó sử dụng công thức này và công thức trên để tính b mod 100000000003 với -b*/bJ+3^T11J. Hàm này được định nghĩa như yvới L.

Tiếp theo, tôi bắt đầu với đầu vào, sau đó đưa nó đến nguồn thứ mười và giảm mod 100000000003, và lặp lại 11 lần này. y^GTlà mã được thực thi trong mỗi bước và uy^GT11Qchạy nó 11 lần bắt đầu với đầu vào.

Bây giờ tôi có Q^(10^11) mod 10^11 + 3, và tôi muốn Q^(10^11 + 1) mod 10^11 + 3, vì vậy tôi nhân với đầu vào với *, giảm mod 100000000003 với ylần cuối và đầu ra.


Thực sự rất tốt đẹp!

Tôi đoán rằng đã quá muộn để tôi thắt chặt các trường hợp thử nghiệm ....

1
@Lembik Tôi sẽ làm điều đó bằng mọi cách, nhưng ý kiến ​​có thể khác nhau. Đó là thử thách của bạn, làm cho nó hoạt động theo cách bạn muốn.
isaacg

Cách viết câu hỏi, có thể bạn có thể bỏ phần giảm cuối cùng, mặc dù tôi đã yêu cầu làm rõ liệu kết quả <100000000003 có bắt buộc không.
Ørjan Johansen

9

Haskell , 118 113 105 101 byte

Lấy cảm hứng từ giải pháp này .

-12 từ Ørjan Johansen

p=10^11+3
k b=((p-2)?b)b 1
r x=x-div x p*p
(e?b)s a|e==0=a|1<2=(div e 2?b$r$s*s)$last$a:[r$a*s|odd e]

Hãy thử trực tuyến!

Haskell , 48 byte

Một bản viết lại của giải pháp này . Mặc dù đủ nhanh cho vectơ thử nghiệm, giải pháp này quá chậm đối với các đầu vào khác.

s x=until(\t->t-t`div`x*x==0)(+(10^11+3))1`div`x

Hãy thử trực tuyến!


Tuyệt vời! Tôi thích sự lũy thừa bằng cách tiếp cận bình phương.
isaacg

Giải pháp ngắn nhất sẽ là một cái gì đó như Thử trực tuyến! nhưng tôi không nghĩ hiệu suất của nó có thể chấp nhận được ...
bartavelle

(1) Nó ngắn hơn để tạo gmột toán tử (e?b)a s|...(2) Nếu bạn chuyển đổi assau đó bạn có thể tạo !một trình điều khiển không hoạt động và nội tuyến yvào nó. (3) Bạn có thể thoát khỏi sự đắt đỏ wherebằng một lastmánh khóe, với chi phí nhân đôi z. Hãy thử trực tuyến!
Ørjan Johansen

Bây giờ đó là những thủ thuật tốt đẹp!
bartavelle

Oh, và |e==0=athoát khỏi sự trùng lặp đáng tiếc đó.
Ørjan Johansen

6

Brachylog , 22 byte

∧10^₁₁+₃;İ≜N&;.×-₁~×N∧

Hãy thử trực tuyến!

Quá trình này mất khoảng 10 phút 1000000với phiên bản mã hơi khác (và dài hơn) nhanh hơn chính xác hai lần (chỉ kiểm tra các giá trị dương İthay vì cả dương và âm). Do đó, việc này sẽ mất khoảng 20 phút để hoàn thành đầu vào đó.

Giải trình

Chúng tôi chỉ đơn giản mô tả điều đó Input × Output - 1 = 100000000003 × an integer, và để cho ràng buộc số học tìm Outputcho chúng tôi.

∧10^₁₁+₃                   100000000003
        ;İ≜N               N = [100000000003, an integer (0, then 1, then -1, then 2, etc.)]
            &;.×           Input × Output…
                -₁         … - 1…
                  ~×N∧     … = the product of the elements of N

Về mặt kỹ thuật, chúng tôi không cần ghi nhãn rõ ràng , tuy nhiên nếu chúng tôi không sử dụng nó, sẽ không kiểm tra trường hợp N = [100000000003,1](vì nó thường vô dụng), có nghĩa là điều này sẽ rất chậm cho đầu vào 2vì nó sẽ cần tìm số nguyên nhỏ thứ hai thay vì đầu tiên


1
Wow, tôi sẽ không bao giờ mong đợi số học ràng buộc để loại bỏ điều đó. Tuyệt vời!
isaacg

1
@isaacg Tốc độ của điều này không may hoàn toàn phụ thuộc vào giá trị của İ, vì vậy điều này vẫn còn khá chậm đối với các sản phẩm lớn.
Gây tử vong vào

Cập nhật câu hỏi. Mã của bạn luôn mất ít hơn 30 phút?

6

Python, 53 51 49 58 53 49 byte

-2 byte nhờ vào orlp
-2 byte nhờ chính thức
-4 byte nhờ Felipe Nardi Batist
-3 byte nhờ isaacg
-1 byte nhờ Ørjan Johansen
-2 byte nhờ Federico Poloni

x=input()
t=1
while t-t/x*x:t+=3+10**11
print t/x

Hãy thử trực tuyến!

Tôi mất ~ 30 phút để tìm ra cái này. Giải pháp của tôi là bắt đầu với số đầu tiên sẽ mod thành 1. Số này là 1. Nếu nó chia hết cho x, thì y là số đó chia cho x. Nếu không, hãy thêm 10000000003 vào số này để tìm số thứ hai mà mod 1000000003 sẽ bằng 1 và lặp lại.


Số đầu tiên sẽ mod thành 1 là 1 ...
orlp

@orlp lol cảm ơn. Điều đó đã tiết kiệm cho tôi 2 byte :)
Zachary Cotton

Thật thú vị, trên TIO, điều này nhanh chóng cho tất cả các trường hợp thử nghiệm nhưng một cú đập bàn phím ngẫu nhiên đã cho tôi biết 421385994thời gian nào.
Ørjan Johansen

@ RjanJohansen Điều tra tốt.

1
Nếu bạn bchỉ cần một lần, tại sao không mã hóa nó?
Federico Poloni

5

JavaScript (ES6), 153 143 141 byte

Lấy cảm hứng từ câu trả lời này từ math.stackexchange.com .

Một hàm đệ quy dựa trên thuật toán Euclide.

f=(n,d=(F=Math.floor,m=1e11+3,a=1,c=n,b=F(m/n),k=m-b*n,n>1))=>k>1&d?(e=F(c/k),a+=e*b,c-=e*k,f(n,c>1&&(e=F(k/c),k-=e*c,b+=e*a,1))):a+d*(m-a-b)

Modulo được thực hiện bằng máy tính:

quotient = Math.floor(a / b);
remainder = a - b * quotient;

Bởi vì thương số cũng cần thiết, làm theo cách đó thực sự có ý nghĩa.

Các trường hợp thử nghiệm


Bạn chỉ cần sàn 64 bit trong lần xuất hiện cuối cùng để bạn có thể thay thế các sàn khác bằng 0 | x / y và xóa khai báo
Oki

5

C ++ 11 (GCC / Clang, Linux), 104 102 byte

using T=__int128_t;T m=1e11+3;T f(T a,T r=1,T n=m-2){return n?f(a*a-a*a/m*m,n&1?r*a-r*a/m*m:r,n/2):r;}

https://ideone.com/gp41rW

Ungolfed, dựa trên định lý Euler và lũy thừa nhị phân.

using T=__int128_t;
T m=1e11+3;
T f(T a,T r=1,T n=m-2){
    if(n){
        if(n & 1){
            return f(a * a - a * a / m * m, r * a - r * a / m * m, n / 2);
        }
        return f(a * a - a * a / m * m, r, n / 2);
    }
    return r;
}

ISO C ++ chỉ yêu cầu longtối thiểu 32 bit, do đó không nhất thiết phải giữ 1e11 + 3. Đó là 32-bit trên Windows x86-64. longlà loại 64 bit trên x86-64 Linux (và các HĐH khác sử dụng SystemV ABI). Vì vậy, để có thể di động hoàn toàn, bạn cần sử dụng long long, được đảm bảo ít nhất là 64 bit kể từ C ++ 11 .
Peter Cordes

__int128_tdường như không phải là C ++ tiêu chuẩn, nó dường như là một phần mở rộng gcc, sẽ rất tuyệt nếu bạn nói đây là ngôn ngữ (C ++ 11 + gcc).
Felix Dombek

3
Đây không phải là một trang web chuyên gia C ++, tôi hy vọng sẽ không có ai chú ý.
SteelRaven

@PeterCordes Code golf không cần phải di động hoặc thậm chí được hình thành tốt, nó chỉ cần hoạt động trên một lần thực hiện.
aschepler

1
@aschepler: Tôi biết, đó là lý do tại sao tôi nói "bạn sẽ cần". Tôi nghĩ rằng nó rất hữu ích để chỉ ra nền tảng nào nó sẽ / sẽ không hoạt động, trong trường hợp bất cứ ai đã thử nó và gặp rắc rối.
Peter Cordes

4

Toán học, 49 byte

x/.FindInstance[x#==k(10^11+3)+1,{x,k},Integers]&

Mất bao lâu để chạy?

Chưa đến 0,001 giây trên máy tính của tôi (đối với trường hợp 2 ^ 40-1)
Keyu Gan


1

Ruby , 58 byte

Bây giờ sử dụng isaacg của định lý Fermat trong khi tôi hoàn thành việc định thời gian cho giải pháp vũ phu.

->n,x=10**11+3{i=n;11.times{i**=10;i-=i/x*x};i*=n;i-i/x*x}

Brute force hiện tại phiên bản, đó là 47 byte nhưng có thể quá chậm:

->n,x=10**11+3{(1..x).find{|i|i*=n;i-i/x*x==1}}

Hãy thử trực tuyến!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.