On vous donne une large plage [a, b] où «a» et «b» peuvent généralement être compris entre 1 et 4 000 000 000 inclus. Vous devez trouver le XOR de tous les nombres dans la plage donnée.
Ce problème a été utilisé dans TopCoder SRM. J'ai vu l'une des solutions proposées dans le match et je ne suis pas en mesure de comprendre comment cela fonctionne.
Quelqu'un pourrait-il vous expliquer la solution gagnante:
long long f(long long a) {
long long res[] = {a,1,a+1,0};
return res[a%4];
}
long long getXor(long long a, long long b) {
return f(b)^f(a-1);
}
Voici getXor()
la fonction réelle pour calculer le xor de tous les nombres dans la plage passée [a, b] et "f ()" est une fonction d'assistance.
a<=0
ou pourb<0
.long long
est un type signé, de même quex%4
négatif (ou 0) pour les entrées négatives . Peut-être voulez-vousunsigned long long
et / oua & 3
indexer le tableau?Réponses:
C'est une solution assez intelligente - elle exploite le fait qu'il existe un modèle de résultats dans les XOR en cours d'exécution. La
f()
fonction calcule la course totale XOR à partir de [0, a]. Jetez un œil à ce tableau pour les nombres 4 bits:Où la première colonne est la représentation binaire, puis le résultat décimal et sa relation avec son index (a) dans la liste XOR. Cela se produit parce que tous les bits supérieurs s'annulent et les deux bits les plus bas effectuent un cycle tous les 4. Voilà comment arriver à cette petite table de recherche.
Maintenant, considérons une plage générale de [a, b]. Nous pouvons utiliser
f()
pour trouver le XOR pour [0, a-1] et [0, b]. Puisque toute valeur XOR'd avec elle-même est zéro, lef(a-1)
juste annule toutes les valeurs dans l'exécution XOR inférieure àa
, vous laissant avec le XOR de la plage [a, b].la source
a
il y a 2, pas 0.Ajoutant à l'excellente réponse de FatalError, la ligne
return f(b)^f(a-1);
pourrait être mieux expliquée. En bref, c'est parce que XOR a ces merveilleuses propriétés:Voici les deux en action:
Comme ça:
Ajouter et multiplier sont deux exemples d'autres opérateurs associatifs / commutatifs, mais ils ne s'inversent pas. Ok, alors, pourquoi ces propriétés sont-elles importantes? Eh bien, un moyen simple est de l'étendre à ce qu'il est vraiment, et vous pourrez ensuite voir ces propriétés à l'œuvre.
Tout d'abord, définissons ce que nous voulons et appelons-le n:
Si cela aide, pensez à XOR (^) comme s'il s'agissait d'un ajout.
Définissons également la fonction:
b
est supérieur àa
, donc simplement en ajoutant en toute sécurité quelques crochets supplémentaires (ce que nous pouvons car c'est associatif), nous pouvons également dire ceci:Ce qui se simplifie en:
Ensuite, nous utilisons cette propriété d'inversion et cette commutivité pour nous donner la ligne magique:
Si vous avez pensé à XOR comme un ajout, vous y auriez ajouté une soustraction. XOR est à XOR ce que ajouter c'est soustraire!
Comment puis-je trouver cela moi-même?
Souvenez-vous des propriétés des opérateurs logiques. Travaillez avec eux presque comme un ajout ou multipliez si cela aide. Il semble inhabituel que et (&), xor (^) et ou (|) soient associatifs, mais ils le sont!
Exécutez d'abord l'implémentation naïve, recherchez des modèles dans la sortie, puis commencez à trouver des règles qui confirment que le modèle est vrai. Simplifiez encore plus votre mise en œuvre et recommencez. C'est probablement la route empruntée par le créateur original, mise en évidence par le fait qu'elle n'est pas complètement optimale (c'est-à-dire utiliser une instruction switch plutôt qu'un tableau).
la source
J'ai découvert que le code ci-dessous fonctionne également comme la solution donnée dans la question.
C'est peut-être peu optimisé, mais c'est exactement ce que j'ai obtenu en observant la répétition comme indiqué dans la réponse acceptée
Je voudrais connaître / comprendre la preuve mathématique derrière le code donné, comme expliqué dans la réponse de @Luke Briggs
Voici ce code JAVA
la source
J'ai résolu le problème de la récursivité. Je divise simplement l'ensemble de données en une partie presque égale pour chaque itération.
Faites-moi savoir ce que vous pensez de la solution. Heureux de recevoir des commentaires d'amélioration. La solution proposée calcule le XOR en complexité 0 (log N).
Je vous remercie
la source
Pour prendre en charge XOR de 0 à N, le code donné devait être modifié comme ci-dessous,
la source