[PYTHON] Problemstudie Memo zu viel verlangt geteilt durch 1000000007

Bei Programmierwettbewerben tritt häufig das Problem auf, den Rest geteilt durch eine Primzahl zu finden, wenn die Antwort sehr groß ist. Ich habe gelernt, über ein solches Problem nachzudenken, deshalb werde ich es zusammenfassen. Der Beispielcode ist im Grunde Python 2.7. Referenz: TopCoder Trends und Gegenmaßnahmen 4 (C ++ Edition: Counting)

Was soll ich machen?

Sie müssen jedes Mal, wenn Sie eine Berechnung durchführen, zu viel verlangen.

Im Falle der Hinzufügung

Fragen Sie nach dem Hinzufügen einfach zu viel.

mod = 1000000007

def add(a, b):
    return (a + b) % mod

Im Falle der Subtraktion

Im Fall von Python können Sie es ohne nachzudenken ziehen und dann zu viel verlangen. Wenn die Sprache zu viel negativen Wert erfordert, gibt es nichts, worüber man vorsichtig sein muss.

mod = 1000000007

def sub(a, b):
    return (a + mod - b) % mod

def sub_(a, b):
    return (a - b) % mod

print sub(1, 2) # => 1000000006
print sub_(1, 2) # => 1000000006

Als ich es mit C versuchte, wurde es ein negativer Wert. In diesem Fall scheint es besser, 1000000007 zu "a" zu addieren und dann "b" zu subtrahieren.

#include <stdio.h>

int mod = 1000000007;

int sub(a, b) {
  return (a + mod - b) % mod;
}

int sub_(a, b) {
  return (a - b) % mod;
}

int main(void){
  printf("%d\n", sub(1, 2)); // => 1000000006
  printf("%d\n", sub_(1, 2)); // => -1
}

Der verwendete Compiler:

$ gcc -v
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 8.0.0 (clang-800.0.38)
Target: x86_64-apple-darwin16.0.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

Im Falle der Multiplikation

Multiplizieren Sie sich zu viel und nehmen Sie mehr.

mod = 1000000007

def mul(a, b):
    return ((a % mod) * (b % mod)) % mod

Im Falle einer Teilung

Plötzlich kommt Fermats kleiner Satz heraus und ich habe Angst. Irgendwie scheint es schwierig. Ich bin mir nicht sicher, ob es sich vorerst um eine Division handelt, daher möchte ich sie auf Multiplikation beschränken.

a \div b = a \times b^{-1}

Das ist es. Deshalb möchte ich die Umkehrung von "b" in der Welt zu sehr finden. Dann verwenden wir den Satz von Fermat, um die Umkehrung zu finden. Wenn Sie sich die Referenzseite ansehen, scheint das Ergebnis "b" für die 1000000005. Potenz zu sein. Mit anderen Worten, in Division sollte die folgende Berechnung durchgeführt werden.

a \div b = a \times b^{1000000005} (mod 1000000007)

Dieses Mal müssen wir eine schwierige Berechnung von "b" mit der Potenz von 1000000005 durchführen, aber wir können hierfür die dichotome Potenzmethode verwenden. Wenn Sie das Quadrat zuerst finden, verwenden Sie es, um die 4. Potenz zu finden, und verwenden Sie es dann, um die 8. Potenz zu finden, und so weiter. Sie können es viel schneller finden, als b mit 1000000005 mal zu multiplizieren. Daher ist es eine Geschichte.

Um das Obige zusammenzufassen, ist die Unterteilung wie folgt.

mod = 1000000007

def mul(a, b):
    return ((a % mod) * (b % mod)) % mod

def power(x, y):
    if   y == 0     : return 1
    elif y == 1     : return x % mod
    elif y % 2 == 0 : return power(x, y/2)**2 % mod
    else            : return power(x, y/2)**2 * x % mod

def div(a, b):
    return mul(a, power(b, mod-2))

print div(6, 3) # => 2
print div(10, 2) # => 5
print div(3000000000, 2) # => 499999993
print div(45000000000, 5) # => 999999944
print div(4000000000, 2000000000) # => 2
print div(45000000000, 5000000000) # => 9

Es sieht gut aus, ist aber nicht intuitiv ...

Ich werde versuchen, ein Problem zu lösen

Ich versuchte es. Es ist ein Problem, die Kombination zu berechnen. AtCoder-Anfängerwettbewerb 042: D - Iroha richtig quadratisch

mod = 1000000007
H, W, A, B = map(int, raw_input().split())

factorial = [1]
for n in xrange(1, H+W):
    factorial.append(factorial[n-1]*n%mod)

def power(x, y):
    if   y == 0     : return 1
    elif y == 1     : return x % mod
    elif y % 2 == 0 : return power(x, y/2)**2 % mod
    else            : return power(x, y/2)**2 * x % mod

inverseFactorial = [0] * (H+W)
inverseFactorial[H+W-1] = power(factorial[H+W-1], mod-2)
for n in xrange(H+W-2, -1, -1):
    inverseFactorial[n] = inverseFactorial[n+1] * (n+1) % mod

def combi(n, m):
    return factorial[n] * inverseFactorial[m] * inverseFactorial[n-m] % mod

sum = 0
for i in xrange(B+1, W+1):
    sum = (sum + combi(H-A-1+i-1, i-1) * combi(A-1+W-i, W-i)) % mod
print sum

Bei der Kombinationsberechnung wird die Division durch die Multiplikation durchgeführt. Suchen Sie daher das inverse Element der Multiplikation, das im Voraus als notwendig erscheint. Wenn Sie zu diesem Zeitpunkt Folgendes berechnen, scheint dies schnell zu sein, da Sie die Leistung von 1000000005 nicht viele Male berechnen müssen.

n!^{-1} = (n+1)!^{-1} \times (n+1)

abschließend

Um ehrlich zu sein, sieht es nicht richtig aus, aber ich denke, es ist wahrscheinlich gemacht, weil ich AC habe. Bis jetzt konnte ich nicht in den Code einsteigen, weil ich Angst vor dem Satz von Fermat hatte, also habe ich das Gefühl, dass ich mich ein wenig vorwärts bewegen konnte.

Recommended Posts

Problemstudie Memo zu viel verlangt geteilt durch 1000000007
Memo, um nach KPI mit Python zu fragen
[Für Anfänger] Wie man Programmierung studiert Private Memo
Python-Lernnotiz für maschinelles Lernen von Chainer Kapitel 10 Einführung in Cupy
Python-Lernnotiz für maschinelles Lernen von Chainer Kapitel 9 Einführung in das Scikit-Lernen
Entscheiden Sie, wen Sie per Lotterie wählen möchten
Python & maschinelles Lernen Lernnotiz Machine: Maschinelles Lernen durch Rückausbreitung