{
  "chapter": {
    "id": "diviser-pour-regner",
    "level": "terminale",
    "theme": "Algorithmique",
    "title": "Diviser pour régner",
    "description": "Paradigme diviser pour régner (étapes diviser, régner, combiner),\nrecherche dichotomique, tri fusion et tri rapide, exponentiation\nrapide, complexité par récurrence et théorème maître.",
    "prerequisites": [],
    "references": []
  },
  "questions": [
    {
      "id": "q01",
      "difficulty": 1,
      "skills": [
        "paradigme",
        "definition"
      ],
      "title": "Étapes du paradigme diviser pour régner",
      "statement": "Quelles sont les **trois étapes** du paradigme diviser pour\nrégner ?",
      "options": [
        {
          "text": "Initialiser, itérer, terminer",
          "correct": false,
          "feedback": "Erreur : ces étapes décrivent une boucle, pas le paradigme\ndiviser pour régner qui est typiquement récursif.\n"
        },
        {
          "text": "Diviser, régner, combiner",
          "correct": true,
          "feedback": "Bonne réponse : on divise le problème en sous-problèmes\nplus petits, on les résout (récursivement), puis on\ncombine les solutions partielles pour obtenir la solution\ndu problème initial.\n"
        },
        {
          "text": "Trier, fusionner, comparer",
          "correct": false,
          "feedback": "Erreur : ces opérations apparaissent dans le tri fusion\n(un cas particulier), mais ne sont pas les trois étapes\ngénérales du paradigme.\n"
        },
        {
          "text": "Identifier, calculer, vérifier",
          "correct": false,
          "feedback": "Erreur : ces verbes décrivent une démarche scientifique\ngénérale, pas la stratégie diviser pour régner.\n"
        }
      ],
      "explanation": "Le paradigme repose sur l'idée que résoudre un sous-problème\nplus petit est plus simple, et que combiner les solutions\npartielles donne efficacement la solution complète. C'est\nl'idée mère de la recherche dichotomique, du tri fusion, de\nl'exponentiation rapide, etc."
    },
    {
      "id": "q02",
      "difficulty": 1,
      "skills": [
        "dichotomie",
        "complexite"
      ],
      "title": "Complexité de la recherche dichotomique",
      "statement": "Quelle est la complexité au pire de la recherche dichotomique\nsur un tableau trié de $n$ éléments ?",
      "options": [
        {
          "text": "$O(\\log n)$",
          "correct": true,
          "feedback": "Bonne réponse : à chaque étape, l'intervalle de recherche\nest divisé par deux. Le nombre d'étapes est donc le\nlogarithme en base $2$ de $n$.\n"
        },
        {
          "text": "$O(n \\log n)$",
          "correct": false,
          "feedback": "Erreur : c'est la complexité du tri fusion, pas d'une\nrecherche.\n"
        },
        {
          "text": "$O(n)$",
          "correct": false,
          "feedback": "Erreur : c'est la complexité de la recherche **linéaire**.\nLa dichotomie est plus rapide grâce au tri préalable.\n"
        },
        {
          "text": "$O(1)$",
          "correct": false,
          "feedback": "Erreur : ce serait une recherche en temps constant, ce\nqui n'est pas réaliste pour rechercher un élément dans\nun tableau de taille variable.\n"
        }
      ],
      "explanation": "Pour $n = 10^9$, la dichotomie effectue au plus $30$\ncomparaisons. C'est l'un des gains algorithmiques les plus\nspectaculaires : passer de linéaire à logarithmique."
    },
    {
      "id": "q03",
      "difficulty": 1,
      "skills": [
        "tri-fusion",
        "principe"
      ],
      "title": "Principe du tri fusion",
      "statement": "Quel est le principe du **tri fusion** ?",
      "options": [
        {
          "text": "Chercher le plus petit élément, le placer en début, recommencer",
          "correct": false,
          "feedback": "Erreur : c'est le principe du tri par sélection.\n"
        },
        {
          "text": "Couper le tableau en deux moitiés, trier chaque moitié récursivement, puis fusionner les deux moitiés triées",
          "correct": true,
          "feedback": "Bonne réponse : c'est l'application directe du paradigme\ndiviser pour régner. La fusion de deux tableaux triés\nse fait en temps linéaire en parcourant les deux\nsimultanément.\n"
        },
        {
          "text": "Insérer chaque élément à sa place dans la portion déjà triée",
          "correct": false,
          "feedback": "Erreur : c'est le principe du tri par insertion.\n"
        },
        {
          "text": "Comparer chaque paire d'éléments adjacents et les permuter si nécessaire",
          "correct": false,
          "feedback": "Erreur : c'est le principe du tri à bulles, en $O(n^2)$.\n"
        }
      ],
      "explanation": "Le tri fusion est l'archétype du tri par diviser pour régner.\nSa complexité $O(n \\log n)$ ne dépend pas de l'ordre initial,\nce qui en fait un tri à comportement **prévisible**."
    },
    {
      "id": "q04",
      "difficulty": 1,
      "skills": [
        "tri-fusion",
        "complexite"
      ],
      "title": "Complexité du tri fusion",
      "statement": "Quelle est la complexité du tri fusion sur un tableau de $n$\néléments ?",
      "options": [
        {
          "text": "$O(n \\log n)$",
          "correct": true,
          "feedback": "Bonne réponse : il y a $\\log n$ niveaux de récursion (on\ndivise par deux à chaque niveau). À chaque niveau, on\nparcourt l'ensemble des $n$ éléments lors des fusions.\nTotal : $n \\log n$.\n"
        },
        {
          "text": "$O(n^2)$",
          "correct": false,
          "feedback": "Erreur : c'est la complexité des tris naïfs (sélection,\ninsertion, bulles). Le tri fusion est meilleur grâce au\nparadigme DPR.\n"
        },
        {
          "text": "$O(2^n)$",
          "correct": false,
          "feedback": "Erreur : aucun tri usuel n'est exponentiel.\n"
        },
        {
          "text": "$O(n)$",
          "correct": false,
          "feedback": "Erreur : la fusion seule est en $O(n)$, mais on la\nrépète sur $\\log n$ niveaux de récursion, ce qui donne\n$O(n \\log n)$ au total.\n"
        }
      ],
      "explanation": "Le tri fusion est **stable** (préserve l'ordre des éléments\négaux) et a une complexité **garantie** $O(n \\log n)$ dans\ntous les cas, ce qui le rend prédictible. Son inconvénient\nprincipal : il n'est **pas en place**."
    },
    {
      "id": "q05",
      "difficulty": 1,
      "skills": [
        "tri-fusion",
        "base"
      ],
      "title": "Cas de base du tri fusion",
      "statement": "Quel est le **cas de base** du tri fusion ?",
      "options": [
        {
          "text": "Un tableau de deux éléments",
          "correct": false,
          "feedback": "Erreur : un tableau de deux éléments peut être mal\ntrié. Il faut soit le diviser à nouveau, soit le trier\ndirectement (cas particulier optimisé).\n"
        },
        {
          "text": "Un tableau trié",
          "correct": false,
          "feedback": "Erreur : on ne sait pas a priori si le tableau est trié\n(sans le parcourir). Le cas de base du tri fusion est\nbasé sur la **taille**, pas sur l'ordre.\n"
        },
        {
          "text": "Un tableau de longueur paire",
          "correct": false,
          "feedback": "Erreur : la parité ne garantit pas qu'un tableau soit\ntrié. Le tri fusion fonctionne pour toute parité.\n"
        },
        {
          "text": "Un tableau de zéro ou un élément",
          "correct": true,
          "feedback": "Bonne réponse : un tableau vide ou de longueur $1$ est\ndéjà trié par définition. La récursion s'arrête à ce\nniveau, sans nouvelle découpe ni fusion.\n"
        }
      ],
      "explanation": "Choisir un cas de base à $0$ ou $1$ élément simplifie le\ncode : on n'a même pas besoin de gérer la division pour ces\ncas. Cela rend la fonction parfaitement récursive."
    },
    {
      "id": "q06",
      "difficulty": 1,
      "skills": [
        "exponentiation-rapide"
      ],
      "title": "Principe de l'exponentiation rapide",
      "statement": "L'**exponentiation rapide** calcule $a^n$ en exploitant\nquelle propriété mathématique ?",
      "options": [
        {
          "text": "$a^n = a^{n-1} \\cdot a$",
          "correct": false,
          "feedback": "Erreur : c'est la définition récursive **naïve** de la\npuissance, en $O(n)$. L'exponentiation rapide va beaucoup\nplus vite.\n"
        },
        {
          "text": "$a^n = a + a + \\cdots + a$ ($n$ fois)",
          "correct": false,
          "feedback": "Erreur : c'est la définition de la multiplication, pas\nde la puissance. L'exponentiation rapide ne peut pas\npartir d'une somme.\n"
        },
        {
          "text": "$a^n = (a^{n/2})^2$ si $n$ est pair, et $a^n = a \\cdot (a^{(n-1)/2})^2$ si $n$ est impair",
          "correct": true,
          "feedback": "Bonne réponse : on divise l'exposant par deux à chaque\nétape (au lieu de soustraire $1$). Cela amène la\ncomplexité de $O(n)$ à $O(\\log n)$.\n"
        },
        {
          "text": "$a^n = n \\cdot a$",
          "correct": false,
          "feedback": "Erreur : c'est la définition de $n \\cdot a$, pas de $a^n$.\nConfusion entre puissance et produit.\n"
        }
      ],
      "explanation": "Pour calculer $a^{20}$ : la méthode naïve fait $19$\nmultiplications, l'exponentiation rapide en fait environ\n$\\log_2(20) \\approx 5$. Le gain devient énorme pour de\ngrands exposants (cryptographie, arithmétique modulaire)."
    },
    {
      "id": "q07",
      "difficulty": 1,
      "skills": [
        "tri-fusion",
        "place"
      ],
      "title": "Tri fusion en place ?",
      "statement": "Le tri fusion est-il un tri **en place** ?",
      "options": [
        {
          "text": "Oui, il modifie le tableau d'origine sans mémoire supplémentaire",
          "correct": false,
          "feedback": "Erreur : le tri fusion utilise des tableaux auxiliaires\n(les moitiés gauche et droite, puis le résultat fusionné).\nSa mémoire supplémentaire est en $O(n)$.\n"
        },
        {
          "text": "Non, il utilise une mémoire supplémentaire proportionnelle à $n$",
          "correct": true,
          "feedback": "Bonne réponse : à chaque niveau de récursion, on crée des\ntableaux pour les moitiés et la fusion. C'est l'un des\ninconvénients du tri fusion, contrairement au tri rapide\nou au tri par insertion.\n"
        },
        {
          "text": "Oui, mais seulement pour des listes de taille paire",
          "correct": false,
          "feedback": "Erreur : la parité n'a aucune influence sur le caractère\nen place ou non.\n"
        },
        {
          "text": "Non, mais il utilise une mémoire constante",
          "correct": false,
          "feedback": "Erreur : la mémoire supplémentaire n'est pas constante,\nelle est proportionnelle à la taille du tableau.\n"
        }
      ],
      "explanation": "Tris en place : par sélection, par insertion, à bulles, tri\nrapide. Tri **non en place** : tri fusion (mémoire\n$O(n)$). Pour de grandes données, cet inconvénient peut\nfaire préférer le tri rapide."
    },
    {
      "id": "q08",
      "difficulty": 1,
      "skills": [
        "dichotomie",
        "prerequis"
      ],
      "title": "Pré-requis de la recherche dichotomique",
      "statement": "Quelle est la condition **indispensable** pour appliquer la\nrecherche dichotomique ?",
      "options": [
        {
          "text": "Le tableau doit être trié",
          "correct": true,
          "feedback": "Bonne réponse : la dichotomie compare l'élément cherché\nau milieu pour décider d'aller à gauche ou à droite. Si\nle tableau n'est pas trié, cette comparaison ne donne\naucune information utile, et l'algorithme peut renvoyer\nun faux négatif.\n"
        },
        {
          "text": "Le tableau doit être de taille puissance de $2$",
          "correct": false,
          "feedback": "Erreur : la taille n'a pas besoin d'être une puissance\nde $2$. La dichotomie fonctionne pour toute taille\n$\\geq 0$.\n"
        },
        {
          "text": "Le tableau doit avoir une taille connue à l'avance",
          "correct": false,
          "feedback": "Erreur : c'est une caractéristique des tableaux Python\nou C en général, pas une contrainte de la dichotomie.\n"
        },
        {
          "text": "Le tableau doit contenir uniquement des entiers",
          "correct": false,
          "feedback": "Erreur : la dichotomie fonctionne sur tout type\ncomparable (entiers, flottants, chaînes, dates, etc.).\n"
        }
      ],
      "explanation": "Si la liste n'est pas triée et que les recherches sont\noccasionnelles, mieux vaut faire une recherche linéaire\nqu'un tri préalable. La dichotomie est rentable quand on\nprévoit de très nombreuses recherches sur la même liste."
    },
    {
      "id": "q09",
      "difficulty": 1,
      "skills": [
        "recursivite-lien"
      ],
      "title": "Récursivité et diviser pour régner",
      "statement": "Pourquoi le paradigme diviser pour régner s'implémente-t-il\nnaturellement par **récursivité** ?",
      "options": [
        {
          "text": "Parce que la récursivité est le seul moyen de coder une boucle en Python",
          "correct": false,
          "feedback": "Erreur : Python permet aussi des boucles `for` et\n`while`. La récursivité est un choix, pas une\nobligation.\n"
        },
        {
          "text": "Parce que le paradigme nécessite la mémoïsation",
          "correct": false,
          "feedback": "Erreur : la mémoïsation concerne la programmation\ndynamique, pas le diviser pour régner classique.\n"
        },
        {
          "text": "Parce que la récursivité est plus rapide que l'itération",
          "correct": false,
          "feedback": "Erreur : la récursivité est en réalité souvent un peu\n**plus lente** (surcoût des appels) en Python. Son\nintérêt est la lisibilité, pas la vitesse.\n"
        },
        {
          "text": "Parce qu'on doit résoudre des sous-problèmes de même nature que le problème initial, ce qui s'exprime naturellement par un appel récursif",
          "correct": true,
          "feedback": "Bonne réponse : la définition même du paradigme implique\nque les sous-problèmes sont de même structure que le\nproblème principal. Une fonction qui s'appelle\nelle-même sur le sous-problème est l'expression la plus\ndirecte.\n"
        }
      ],
      "explanation": "Certains algorithmes DPR ont des versions itératives plus\nefficaces (recherche dichotomique itérative, exponentiation\nrapide itérative), mais la version récursive est souvent\nplus claire pédagogiquement."
    },
    {
      "id": "q10",
      "difficulty": 1,
      "skills": [
        "tri-fusion",
        "fusion"
      ],
      "title": "Fusion de deux listes triées",
      "statement": "Pour fusionner deux listes **déjà triées** de longueur $n$\nchacune en une seule liste triée, quelle est la complexité\nde l'opération ?",
      "options": [
        {
          "text": "$O(n^2)$",
          "correct": false,
          "feedback": "Erreur : on n'a pas besoin de comparer chaque élément à\ntous les autres, seulement aux candidats en tête de\nchaque liste.\n"
        },
        {
          "text": "$O(n \\log n)$",
          "correct": false,
          "feedback": "Erreur : c'est la complexité du tri fusion **complet**,\npas de la seule fusion. La fusion est l'étape\n« combiner » du paradigme.\n"
        },
        {
          "text": "$O(n)$",
          "correct": true,
          "feedback": "Bonne réponse : on parcourt les deux listes\nsimultanément avec un index pour chacune. Chaque\ncomparaison fait avancer l'un des deux index. Au total,\non fait $2n$ pas, soit $O(n)$.\n"
        },
        {
          "text": "$O(1)$",
          "correct": false,
          "feedback": "Erreur : il faut quand même parcourir les éléments des\ndeux listes au moins une fois pour les disposer dans\nl'ordre.\n"
        }
      ],
      "explanation": "C'est précisément cette fusion en $O(n)$ par niveau, répétée\nsur $\\log n$ niveaux, qui donne la complexité globale en\n$O(n \\log n)$ du tri fusion."
    },
    {
      "id": "q11",
      "difficulty": 2,
      "skills": [
        "dichotomie",
        "evaluation"
      ],
      "title": "Nombre de comparaisons en dichotomie",
      "statement": "Combien de comparaisons effectue **au pire** une recherche\ndichotomique sur un tableau de $1\\ 000$ éléments ?",
      "options": [
        {
          "text": "$1$",
          "correct": false,
          "feedback": "Erreur : on ne peut pas garantir une seule comparaison\ndans le pire cas. Le pire cas atteint $\\lceil \\log_2 n \\rceil$\ncomparaisons.\n"
        },
        {
          "text": "$500$",
          "correct": false,
          "feedback": "Erreur : la première étape de la dichotomie élimine la\nmoitié des candidats, mais on continue à diviser\nensuite. Le total est bien plus faible que $500$.\n"
        },
        {
          "text": "$1\\ 000$",
          "correct": false,
          "feedback": "Erreur : c'est le nombre maximal de comparaisons d'une\nrecherche **linéaire**. La dichotomie est bien plus\nrapide.\n"
        },
        {
          "text": "Environ $10$",
          "correct": true,
          "feedback": "Bonne réponse : $\\log_2(1\\ 000) \\approx 9{,}97$. Au\npire, $10$ comparaisons suffisent pour trouver l'élément\nou conclure à son absence.\n"
        }
      ],
      "explanation": "Repère utile : doubler la taille n'ajoute qu'**une**\ncomparaison. Pour passer de $1\\ 000$ à $2\\ 000$, on passe de\n$10$ à $11$ comparaisons. C'est ce qui rend les algorithmes\nlogarithmiques exceptionnellement rapides à grande échelle."
    },
    {
      "id": "q12",
      "difficulty": 2,
      "skills": [
        "tri-fusion",
        "deroulement"
      ],
      "title": "Tri fusion sur un exemple",
      "statement": "Si l'on applique le tri fusion à la liste $[5, 2, 8, 3, 9, 1]$,\nquelle est la première étape ?",
      "options": [
        {
          "text": "Diviser la liste en $[5, 2, 8]$ et $[3, 9, 1]$",
          "correct": true,
          "feedback": "Bonne réponse : on coupe la liste au milieu en deux\nsous-listes de taille (presque) égale. Chaque moitié\nsera triée récursivement avant la fusion finale.\n"
        },
        {
          "text": "Trouver le plus petit élément ($1$) et le placer en début",
          "correct": false,
          "feedback": "Erreur : c'est le tri par sélection. Le tri fusion ne\ncherche pas le minimum, il découpe la liste en deux.\n"
        },
        {
          "text": "Trier la liste avec une fonction `sorted` intégrée",
          "correct": false,
          "feedback": "Erreur : utiliser `sorted` éviterait l'algorithme\nétudié. La question porte sur le déroulement du tri\nfusion lui-même.\n"
        },
        {
          "text": "Comparer $5$ et $2$, les permuter",
          "correct": false,
          "feedback": "Erreur : c'est l'opération du tri à bulles. Le tri\nfusion ne fait pas de comparaisons adjacentes au début.\n"
        }
      ],
      "explanation": "Après division récursive, on obtient des sous-listes de\ntaille $1$ (déjà triées). Puis les fusions remontent en\nreconstituant des sous-listes triées de plus en plus\ngrandes : $[2, 5]$, $[2, 5, 8]$, etc. jusqu'au tableau\ncomplet trié."
    },
    {
      "id": "q13",
      "difficulty": 2,
      "skills": [
        "exponentiation-rapide",
        "complexite"
      ],
      "title": "Complexité de l'exponentiation rapide",
      "statement": "Quelle est la complexité de l'exponentiation rapide pour\ncalculer $a^n$ ?",
      "options": [
        {
          "text": "$O(1)$",
          "correct": false,
          "feedback": "Erreur : la complexité dépend bien de $n$. Pour $n$\ntrès grand, le calcul nécessite plusieurs étapes.\n"
        },
        {
          "text": "$O(n)$",
          "correct": false,
          "feedback": "Erreur : c'est la complexité de la méthode **naïve**\n($a^n = a \\cdot a^{n-1}$, $n - 1$ multiplications).\nL'exponentiation rapide divise par deux au lieu de\ndécrémenter de $1$.\n"
        },
        {
          "text": "$O(\\log n)$",
          "correct": true,
          "feedback": "Bonne réponse : à chaque appel récursif, on divise\nl'exposant par deux. Il y a donc environ $\\log_2 n$\nniveaux d'appels, donc autant de multiplications.\n"
        },
        {
          "text": "$O(n^2)$",
          "correct": false,
          "feedback": "Erreur : aucune raison d'avoir une complexité quadratique\npour ce calcul.\n"
        }
      ],
      "explanation": "Pour $n = 10^{18}$, la méthode naïve ferait $10^{18} - 1$\nmultiplications (impossible). L'exponentiation rapide n'en\nfait qu'une soixantaine. Indispensable en cryptographie\nasymétrique (RSA)."
    },
    {
      "id": "q14",
      "difficulty": 2,
      "skills": [
        "recurrence",
        "calcul"
      ],
      "title": "Récurrence du tri fusion",
      "statement": "Soit $T(n)$ le nombre d'opérations du tri fusion sur un\ntableau de $n$ éléments. Quelle relation de récurrence\nvérifie $T(n)$ ?",
      "options": [
        {
          "text": "$T(n) = T(n/2) + 1$",
          "correct": false,
          "feedback": "Erreur : c'est la récurrence de la **dichotomie** (un\nseul appel récursif sur la moitié). Le tri fusion en\nfait deux.\n"
        },
        {
          "text": "$T(n) = T(n-1) + 1$",
          "correct": false,
          "feedback": "Erreur : cette récurrence donne $T(n) = O(n)$, ce qui\nest trop optimiste pour le tri fusion.\n"
        },
        {
          "text": "$T(n) = 2 \\cdot T(n/2) + n$",
          "correct": true,
          "feedback": "Bonne réponse : on appelle deux fois la fonction sur des\nmoitiés (les $2 \\cdot T(n/2)$), puis on fusionne en\n$O(n)$ opérations. Le théorème maître donne\n$T(n) = O(n \\log n)$.\n"
        },
        {
          "text": "$T(n) = T(n-1) + T(n-2)$",
          "correct": false,
          "feedback": "Erreur : c'est la récurrence de Fibonacci. Le tri\nfusion ne dépend pas des deux étapes précédentes.\n"
        }
      ],
      "explanation": "Cette récurrence est l'archétype du « théorème maître » en\nanalyse de complexité : elle apparaît dans tous les\nalgorithmes DPR qui divisent en deux et combinent en\n$O(n)$."
    },
    {
      "id": "q15",
      "difficulty": 2,
      "skills": [
        "tri-fusion",
        "stabilite"
      ],
      "title": "Stabilité du tri fusion",
      "statement": "Le tri fusion est-il un tri **stable** ?",
      "options": [
        {
          "text": "Oui, à condition d'utiliser `<=` plutôt que `<` dans la fonction de fusion",
          "correct": true,
          "feedback": "Bonne réponse : le tri fusion est stable si la fusion\nchoisit l'élément de gauche en cas d'égalité. Cela\npréserve l'ordre relatif des éléments égaux.\n"
        },
        {
          "text": "La notion de stabilité ne s'applique qu'aux tris itératifs",
          "correct": false,
          "feedback": "Erreur : la stabilité est une notion qui s'applique à\ntout tri, indépendamment de son implémentation.\n"
        },
        {
          "text": "Cela dépend de la taille de la liste",
          "correct": false,
          "feedback": "Erreur : la stabilité d'un algorithme ne dépend pas de\nla taille de l'entrée, mais de sa structure.\n"
        },
        {
          "text": "Non, le tri fusion ne préserve pas l'ordre des éléments égaux",
          "correct": false,
          "feedback": "Erreur : il l'est, à condition d'écrire correctement la\nfonction de fusion.\n"
        }
      ],
      "explanation": "La stabilité importe quand on trie des données déjà triées\npar un autre critère. Par exemple, trier des étudiants par\nmoyenne après les avoir triés par nom : un tri stable\nconserve l'ordre alphabétique parmi les ex-aequo."
    },
    {
      "id": "q16",
      "difficulty": 2,
      "skills": [
        "comparaison"
      ],
      "title": "Tri fusion vs tri par insertion",
      "statement": "Pour trier un tableau de $1\\ 000\\ 000$ éléments, le tri\nfusion ($O(n \\log n)$) est environ combien de fois plus\nrapide que le tri par insertion ($O(n^2)$) ?",
      "options": [
        {
          "text": "Environ $50\\ 000$ fois",
          "correct": true,
          "feedback": "Bonne réponse : pour $n = 10^6$, $n^2 = 10^{12}$ et\n$n \\log_2 n \\approx 2 \\cdot 10^7$. Le rapport est\nenviron $50\\ 000$. C'est la différence entre une seconde\net $14$ heures sur la même machine.\n"
        },
        {
          "text": "$1\\ 000\\ 000$ fois",
          "correct": false,
          "feedback": "Erreur : ce serait le rapport $n^2 / n = n$, mais on\ndivise par $n \\log n$, pas par $n$.\n"
        },
        {
          "text": "$2$ fois",
          "correct": false,
          "feedback": "Erreur : la différence est bien plus grande. $\\log_2 n$\nn'est qu'une fraction de $n$ pour de grandes valeurs.\n"
        },
        {
          "text": "$10$ fois",
          "correct": false,
          "feedback": "Erreur : la différence est de plusieurs ordres de\ngrandeur, pas un seul facteur $10$.\n"
        }
      ],
      "explanation": "Cette différence d'ordre de grandeur explique pourquoi le\nchoix de l'algorithme est crucial. Sur petites entrées, les\ntris simples sont compétitifs ; sur grandes entrées, les\ntris en $O(n \\log n)$ deviennent indispensables."
    },
    {
      "id": "q17",
      "difficulty": 2,
      "skills": [
        "exponentiation-rapide",
        "optimisation"
      ],
      "title": "Optimisation par mémoïsation",
      "statement": "Dans une implémentation **récursive** d'exponentiation\nrapide, est-il utile d'ajouter de la **mémoïsation** ?",
      "options": [
        {
          "text": "Oui, cela accélère le calcul",
          "correct": false,
          "feedback": "Erreur : à chaque appel, on calcule une seule valeur\nintermédiaire (`demi = puissance(a, n // 2)`), pas la\nmême plusieurs fois. La mémoïsation n'apporterait rien.\n"
        },
        {
          "text": "Non, l'exponentiation rapide ne fait pas d'appels redondants",
          "correct": true,
          "feedback": "Bonne réponse : à chaque appel, le sous-problème est\nunique (un seul exposant intermédiaire est calculé). Il\nn'y a donc aucun calcul redondant, contrairement à\nFibonacci naïf.\n"
        },
        {
          "text": "Oui, mais seulement pour des exposants pairs",
          "correct": false,
          "feedback": "Erreur : la mémoïsation n'est utile que s'il y a des\nappels redondants, ce qui n'est pas le cas ici.\n"
        },
        {
          "text": "Cela rendrait l'algorithme plus lent",
          "correct": false,
          "feedback": "Erreur : la mémoïsation seule ne ralentit pas\nsignificativement, mais l'avantage est nul ici.\n"
        }
      ],
      "explanation": "La distinction est cruciale : le diviser pour régner peut\navoir des sous-problèmes redondants (cas de Fibonacci) ou\nuniques (cas de l'exponentiation rapide). Seul le premier\nbénéficie de la mémoïsation."
    },
    {
      "id": "q18",
      "difficulty": 2,
      "skills": [
        "dichotomie",
        "code"
      ],
      "title": "Détection d'une erreur dans la dichotomie",
      "statement": "Dans la fonction suivante :\n\n```\ndef recherche(x, tab):\n    gauche, droite = 0, len(tab) - 1\n    while gauche < droite:        # ← ICI\n        milieu = (gauche + droite) // 2\n        if tab[milieu] == x:\n            return milieu\n        elif tab[milieu] < x:\n            gauche = milieu + 1\n        else:\n            droite = milieu - 1\n    return -1\n```\n\nQuel est le bug ?",
      "options": [
        {
          "text": "Il manque l'initialisation de `milieu` avant la boucle",
          "correct": false,
          "feedback": "Erreur : `milieu` est défini à l'intérieur de la boucle,\nce qui est la convention habituelle.\n"
        },
        {
          "text": "La condition de boucle devrait être `gauche <= droite` (avec `<=` au lieu de `<`)",
          "correct": true,
          "feedback": "Bonne réponse : avec `<` strict, on n'examine pas le\ndernier élément quand `gauche == droite`. La fonction\npeut renvoyer $-1$ pour un élément qui est en réalité\nprésent.\n"
        },
        {
          "text": "Le calcul de `milieu` est incorrect",
          "correct": false,
          "feedback": "Erreur : le calcul `(gauche + droite) // 2` est\nstandard et correct. Le bug est ailleurs.\n"
        },
        {
          "text": "La fonction devrait être récursive pour fonctionner",
          "correct": false,
          "feedback": "Erreur : la dichotomie peut s'écrire en itératif comme\nen récursif. La forme itérative est même souvent\npréférée.\n"
        }
      ],
      "explanation": "Erreur subtile et classique. Test concret : avec\n`tab = [5]` et `x = 5`, on a `gauche = droite = 0`, la\ncondition `gauche < droite` est fausse, on sort\nimmédiatement et on renvoie $-1$ alors que $x$ est présent."
    },
    {
      "id": "q19",
      "difficulty": 2,
      "skills": [
        "tri-rapide"
      ],
      "title": "Tri rapide vs tri fusion",
      "statement": "Quelle est la principale différence entre le **tri rapide**\n(*quicksort*) et le tri fusion ?",
      "options": [
        {
          "text": "Le tri rapide est toujours plus rapide que le tri fusion",
          "correct": false,
          "feedback": "Erreur : ce n'est pas systématique. Sur certaines\nentrées (déjà triées avec mauvais pivot), il est même\nbeaucoup plus lent.\n"
        },
        {
          "text": "Le tri rapide est en place mais sa complexité au pire est $O(n^2)$, alors que le tri fusion est $O(n \\log n)$ garanti mais pas en place",
          "correct": true,
          "feedback": "Bonne réponse : le tri rapide partitionne autour d'un\npivot et est en place, mais avec un mauvais pivot, il\ndégénère à $O(n^2)$. Le tri fusion garantit\n$O(n \\log n)$ mais utilise plus de mémoire.\n"
        },
        {
          "text": "Le tri rapide est plus simple à comprendre",
          "correct": false,
          "feedback": "Erreur : ces deux algorithmes ont une difficulté\ncomparable. Ce n'est pas la raison de leur distinction.\n"
        },
        {
          "text": "Le tri rapide ne fonctionne que sur les entiers",
          "correct": false,
          "feedback": "Erreur : les deux fonctionnent sur tout type comparable.\n"
        }
      ],
      "explanation": "Choisir entre les deux dépend du contexte : tri rapide pour\ngagner de la mémoire (et accepter le risque du pire cas),\ntri fusion pour la prévisibilité. Les bibliothèques\nstandard utilisent souvent des tris hybrides comme\nTimsort."
    },
    {
      "id": "q20",
      "difficulty": 2,
      "skills": [
        "diviser",
        "decoupage"
      ],
      "title": "Découpage déséquilibré",
      "statement": "Que se passe-t-il si le découpage en sous-problèmes est très\n**déséquilibré** (par exemple, une moitié contenant $1$\nélément et l'autre $n-1$ éléments) ?",
      "options": [
        {
          "text": "La complexité reste $O(n)$",
          "correct": false,
          "feedback": "Erreur : un découpage déséquilibré ne réduit pas la\ntaille suffisamment vite pour rester en $O(n)$.\n"
        },
        {
          "text": "La complexité reste en $O(n \\log n)$",
          "correct": false,
          "feedback": "Erreur : la complexité $O(n \\log n)$ suppose un\ndécoupage **équilibré** (en deux moitiés de même taille).\nUn découpage déséquilibré dégrade fortement la\nperformance.\n"
        },
        {
          "text": "La complexité dégénère à $O(n^2)$",
          "correct": true,
          "feedback": "Bonne réponse : avec ce découpage, on a $n$ niveaux de\nrécursion (au lieu de $\\log n$), chacun coûtant $O(n)$.\nLe total devient $O(n^2)$. C'est exactement ce qui se\nproduit avec un mauvais pivot dans le tri rapide.\n"
        },
        {
          "text": "L'algorithme ne termine pas",
          "correct": false,
          "feedback": "Erreur : tant que le découpage diminue strictement la\ntaille du sous-problème, l'algorithme termine. Le\nproblème est la **performance**, pas la terminaison.\n"
        }
      ],
      "explanation": "C'est pour cette raison que le choix du **pivot** est\ncrucial dans le tri rapide. Des stratégies sont utilisées\n(médian de trois, pivot aléatoire) pour éviter les pires\ncas pratiques."
    },
    {
      "id": "q21",
      "difficulty": 3,
      "skills": [
        "theoreme-maitre"
      ],
      "title": "Application du théorème maître",
      "statement": "Soit la récurrence $T(n) = 4 \\cdot T(n/2) + n$. Quelle est la\ncomplexité asymptotique de $T(n)$ ?",
      "options": [
        {
          "text": "$O(n)$",
          "correct": false,
          "feedback": "Erreur : avec $4$ sous-problèmes de taille $n/2$ chacun,\nla complexité dépasse $O(n)$. À chaque niveau on\nquadruple le nombre d'appels.\n"
        },
        {
          "text": "$O(n^4)$",
          "correct": false,
          "feedback": "Erreur : $4^{\\log_2 n} = n^{\\log_2 4} = n^2$, pas $n^4$.\n"
        },
        {
          "text": "$O(n \\log n)$",
          "correct": false,
          "feedback": "Erreur : c'est le résultat pour $T(n) = 2 T(n/2) + n$,\npas $4 T(n/2) + n$.\n"
        },
        {
          "text": "$O(n^2)$",
          "correct": true,
          "feedback": "Bonne réponse : avec $4$ appels sur des moitiés, on a un\narbre d'appels qui croît comme $4^{\\log_2 n} = n^2$.\nC'est en effet la complexité du tri par sélection\nversion DPR sans optimisation.\n"
        }
      ],
      "explanation": "Le théorème maître donne $T(n) = O(n^{\\log_b a})$ pour la\nrécurrence $T(n) = a T(n/b) + O(n^c)$ quand $\\log_b a > c$.\nIci $a = 4$, $b = 2$, $c = 1$ : on a $\\log_2 4 = 2 > 1$,\ndonc $O(n^2)$."
    },
    {
      "id": "q22",
      "difficulty": 3,
      "skills": [
        "recursivite",
        "pile"
      ],
      "title": "Profondeur de la pile en tri fusion",
      "statement": "Pour trier un tableau de $1\\ 000$ éléments par tri fusion\nrécursif, quelle est la **profondeur maximale** de la pile\nd'appels ?",
      "options": [
        {
          "text": "$500$",
          "correct": false,
          "feedback": "Erreur : confusion possible avec « la moitié ». La\nprofondeur n'est pas $n/2$ mais bien $\\log n$.\n"
        },
        {
          "text": "Environ $10$",
          "correct": true,
          "feedback": "Bonne réponse : $\\log_2(1\\ 000) \\approx 10$. La pile\nd'appels reste donc très peu profonde, ce qui évite\nles `RecursionError` même pour de grandes entrées.\n"
        },
        {
          "text": "$1$",
          "correct": false,
          "feedback": "Erreur : un seul appel ne suffit pas à diviser\n$1\\ 000$ éléments jusqu'au cas de base.\n"
        },
        {
          "text": "$1\\ 000$",
          "correct": false,
          "feedback": "Erreur : on ne descend pas $1\\ 000$ niveaux. Le\ndécoupage divise par deux à chaque niveau, donc la\nprofondeur croît comme $\\log n$.\n"
        }
      ],
      "explanation": "C'est une autre force du diviser pour régner avec\ndécoupage équilibré : la profondeur logarithmique évite\ntout problème de débordement de pile, même pour des\nmilliards d'éléments."
    },
    {
      "id": "q23",
      "difficulty": 3,
      "skills": [
        "exponentiation",
        "application"
      ],
      "title": "Exponentiation modulaire",
      "statement": "Pour calculer $a^n \\mod m$ avec de très grands entiers\n(cryptographie), la méthode efficace est :",
      "options": [
        {
          "text": "Appliquer l'exponentiation rapide en réduisant modulo $m$ à chaque multiplication",
          "correct": true,
          "feedback": "Bonne réponse : $(a \\cdot b) \\mod m = ((a \\mod m) \\cdot (b \\mod m)) \\mod m$,\ndonc on peut réduire à chaque étape sans changer le\nrésultat final. Cela maintient les entiers\nintermédiaires petits ($< m^2$), tout en bénéficiant\nde la complexité $O(\\log n)$.\n"
        },
        {
          "text": "Calculer $a^n$ entièrement, puis prendre le modulo",
          "correct": false,
          "feedback": "Erreur : pour $a = 1024$ et $n = 10^9$, $a^n$ a plus\nd'un milliard de chiffres et n'est pas calculable en\npratique. Il faut prendre le modulo à chaque étape.\n"
        },
        {
          "text": "Utiliser une recherche dichotomique sur les diviseurs de $m$",
          "correct": false,
          "feedback": "Erreur : la recherche dichotomique n'a aucun rapport\navec ce calcul.\n"
        },
        {
          "text": "Utiliser le tri fusion sur les chiffres décimaux",
          "correct": false,
          "feedback": "Erreur : aucun rapport entre tri et exponentiation\nmodulaire.\n"
        }
      ],
      "explanation": "L'exponentiation modulaire rapide est l'opération\nfondamentale du chiffrement RSA. Elle permet de calculer\n$a^n \\mod m$ pour des entiers de plusieurs milliers de\nbits, en quelques millisecondes."
    },
    {
      "id": "q24",
      "difficulty": 3,
      "skills": [
        "analyse"
      ],
      "title": "Analyse d'un nouvel algorithme DPR",
      "statement": "On invente un algorithme qui, pour un tableau de $n$\néléments, le découpe en **trois tiers**, traite chaque tiers\nrécursivement, puis fait un travail $O(n)$ pour combiner.\nQuelle est sa complexité ?",
      "options": [
        {
          "text": "$O(n^3)$",
          "correct": false,
          "feedback": "Erreur : on découpe en trois, mais chaque sous-problème\nfait $1/3$ de la taille originale, pas $n/2$. Le\nrésultat reste $O(n \\log n)$.\n"
        },
        {
          "text": "$O(n)$",
          "correct": false,
          "feedback": "Erreur : la combinaison à elle seule est en $O(n)$, mais\nil y a aussi $\\log_3 n$ niveaux à parcourir.\n"
        },
        {
          "text": "$O(3^n)$",
          "correct": false,
          "feedback": "Erreur : la complexité exponentielle apparaît avec des\nappels qui ne réduisent pas la taille. Ici, on divise\nla taille à chaque étape.\n"
        },
        {
          "text": "$O(n \\log_3 n)$",
          "correct": true,
          "feedback": "Bonne réponse : la récurrence est\n$T(n) = 3 T(n/3) + O(n)$. Le théorème maître donne\n$T(n) = O(n \\log n)$ (le facteur $\\log_3$ étant\néquivalent à $\\log_2$ à une constante près).\n"
        }
      ],
      "explanation": "En général, $a$ sous-problèmes de taille $n/b$ avec une\ncombinaison en $O(n)$ donne $O(n \\log n)$ tant que\n$\\log_b a = 1$. C'est la « zone d'équilibre » du théorème\nmaître."
    },
    {
      "id": "q25",
      "difficulty": 3,
      "skills": [
        "synthese"
      ],
      "title": "Reconnaître un algorithme DPR",
      "statement": "Parmi les algorithmes suivants, lequel **n'est pas** un\nalgorithme diviser pour régner ?",
      "options": [
        {
          "text": "Le tri par insertion",
          "correct": true,
          "feedback": "Bonne réponse : le tri par insertion ne divise pas le\nproblème. Il itère sur les éléments et place chacun à\nsa place dans la portion déjà triée. C'est un\nalgorithme **itératif** classique, pas un DPR.\n"
        },
        {
          "text": "L'exponentiation rapide",
          "correct": false,
          "feedback": "Erreur : c'est un DPR. On réduit l'exposant de moitié\nà chaque appel.\n"
        },
        {
          "text": "La recherche dichotomique",
          "correct": false,
          "feedback": "Erreur : c'est aussi un DPR. On divise l'intervalle de\nrecherche par deux à chaque étape.\n"
        },
        {
          "text": "Le tri fusion",
          "correct": false,
          "feedback": "Erreur : c'est un cas d'école du paradigme. On découpe\nen deux moitiés, on trie chaque moitié récursivement,\non fusionne.\n"
        }
      ],
      "explanation": "Pour identifier un DPR, chercher : (1) un découpage en\nsous-problèmes plus petits de même nature, (2) une\nrésolution récursive, (3) une étape de combinaison. Le tri\npar insertion ne fait pas de découpage récursif, donc ce\nn'est pas un DPR."
    },
    {
      "id": "q26",
      "difficulty": 2,
      "skills": [
        "exponentiation-rapide",
        "code"
      ],
      "title": "Code de l'exponentiation rapide",
      "statement": "Quel code Python implémente correctement\nl'exponentiation rapide récursive de $a$ à la\npuissance $n$ (avec $n \\geq 0$) ?",
      "options": [
        {
          "text": "```\ndef puissance(a, n):\n    if n == 0:\n        return 1\n    if n % 2 == 0:\n        return puissance(a, n // 2) * puissance(a, n // 2)\n    return a * puissance(a, n // 2) * puissance(a, n // 2)\n```\n",
          "correct": false,
          "feedback": "Erreur : on calcule **deux fois** la même puissance\nau lieu de la stocker dans une variable. La\ncomplexité retombe à $O(n)$, ce qui annule l'avantage\nde l'exponentiation rapide. Bug classique du\ndébutant.\n"
        },
        {
          "text": "```\ndef puissance(a, n):\n    if n == 0:\n        return 1\n    return a * puissance(a, n - 1)\n```\n",
          "correct": false,
          "feedback": "Erreur : c'est l'exponentiation **naïve**, en\n$O(n)$ multiplications. Elle décrémente l'exposant\nde $1$ à chaque étape au lieu de le diviser par\ndeux. La question demandait l'exponentiation\n**rapide**.\n"
        },
        {
          "text": "```\ndef puissance(a, n):\n    return a ** n\n```\n",
          "correct": false,
          "feedback": "Erreur : on utilise l'opérateur Python intégré, ce\nqui n'illustre pas le paradigme étudié. La question\nportait sur l'écriture **explicite** de\nl'exponentiation rapide.\n"
        },
        {
          "text": "```\ndef puissance(a, n):\n    if n == 0:\n        return 1\n    demi = puissance(a, n // 2)\n    if n % 2 == 0:\n        return demi * demi\n    return a * demi * demi\n```\n",
          "correct": true,
          "feedback": "Bonne réponse : on calcule **une seule fois** la\npuissance pour la moitié de l'exposant, puis on\nmultiplie ce résultat par lui-même (et par `a`\nsupplémentaire si `n` est impair). Complexité\n$O(\\log n)$ multiplications.\n"
        }
      ],
      "explanation": "Idée centrale : sauvegarder le résultat de\n`puissance(a, n // 2)` dans une variable. Sans cette\nmémorisation, l'algorithme dégénère en\nexponentiation naïve. C'est l'illustration la plus\nsimple du diviser pour régner sur un seul\nsous-problème."
    },
    {
      "id": "q27",
      "difficulty": 2,
      "skills": [
        "tri-rapide",
        "partition"
      ],
      "title": "Partition du tri rapide",
      "statement": "Dans le tri rapide, l'opération de\n**partitionnement** autour d'un pivot consiste à :",
      "options": [
        {
          "text": "Réorganiser le tableau de sorte que tous les\néléments inférieurs au pivot soient à sa\ngauche, et tous les éléments supérieurs à sa\ndroite ; le pivot lui-même est alors à sa position\nfinale dans le tableau trié\n",
          "correct": true,
          "feedback": "Bonne réponse : c'est l'étape clé du tri rapide.\nUne fois le pivot positionné, on trie récursivement\nchacune des deux moitiés. La partition se fait en\n$O(n)$ avec un parcours linéaire.\n"
        },
        {
          "text": "Diviser le tableau en deux parties de taille égale\n",
          "correct": false,
          "feedback": "Erreur : c'est ce que fait le tri **fusion**, pas\nle tri rapide. Le tri rapide partitionne autour\nd'une valeur (le pivot), pas autour de la position\nmédiane. Les deux moitiés peuvent être de tailles\ntrès différentes.\n"
        },
        {
          "text": "Compter le nombre d'inversions dans le tableau\n",
          "correct": false,
          "feedback": "Erreur : compter les inversions est une opération\nd'analyse, pas une étape du tri rapide. Aucun lien\navec le partitionnement.\n"
        },
        {
          "text": "Trier la liste avant de choisir un pivot\n",
          "correct": false,
          "feedback": "Erreur : ce serait absurde, puisque le but du tri\nrapide est précisément de trier. La partition est\nune étape **préliminaire** au tri, sans tri\npréalable.\n"
        }
      ],
      "explanation": "Conséquence : si le pivot est mal choisi (extremum), la\npartition peut produire deux moitiés très\ndéséquilibrées (par exemple $0$ et $n-1$ éléments), ce\nqui dégrade la complexité à $O(n^2)$. C'est pourquoi\nle choix du pivot (médiane, aléatoire) est crucial."
    },
    {
      "id": "q28",
      "difficulty": 3,
      "skills": [
        "theoreme-maitre",
        "application"
      ],
      "title": "DPR sans combinaison coûteuse",
      "statement": "La recherche dichotomique satisfait la récurrence\n$T(n) = T(n/2) + O(1)$. Pourquoi obtient-on\n$O(\\log n)$ et non $O(n \\log n)$ comme dans le tri\nfusion ?",
      "options": [
        {
          "text": "Parce qu'il n'y a qu'un seul sous-problème à\nchaque appel (au lieu de deux), et que la\ncombinaison se fait en temps constant $O(1)$\n(au lieu de $O(n)$)\n",
          "correct": true,
          "feedback": "Bonne réponse : la dichotomie ne fait qu'**un seul**\nappel récursif (sur la moitié pertinente) et la\ncombinaison se résume à un test d'égalité ou de\ncomparaison. La somme géométrique des coûts donne\n$O(\\log n)$. Au tri fusion, on a deux appels et une\nfusion en $O(n)$, ce qui donne $O(n \\log n)$.\n"
        },
        {
          "text": "Parce que la recherche dichotomique n'est pas un\nalgorithme diviser pour régner\n",
          "correct": false,
          "feedback": "Erreur : elle relève bien du paradigme. Elle\ndivise l'espace de recherche par deux à chaque\nappel, illustration classique du DPR.\n"
        },
        {
          "text": "Parce que la recherche dichotomique fonctionne\nuniquement sur des tableaux de taille puissance de\ndeux\n",
          "correct": false,
          "feedback": "Erreur : la recherche dichotomique fonctionne pour\ntoute taille. Cette propriété n'a aucun rapport\navec sa complexité.\n"
        },
        {
          "text": "Parce que les comparaisons sont gratuites en Python\n",
          "correct": false,
          "feedback": "Erreur : les comparaisons coûtent du temps comme\ntoute opération. Mais elles sont en nombre\nconstant à chaque appel récursif, ce qui fait la\ndifférence avec une fusion en $O(n)$.\n"
        }
      ],
      "explanation": "Schéma général : pour la récurrence\n$T(n) = a \\cdot T(n/b) + O(n^c)$ : si $a < b^c$, le\ncoût est dominé par la combinaison, complexité\n$O(n^c)$ ; si $a = b^c$, on a $O(n^c \\log n)$ ; si\n$a > b^c$, on a $O(n^{\\log_b a})$. Pour la\ndichotomie : $a = 1$, $b = 2$, $c = 0$, donc\n$a = b^c = 1$, complexité $O(\\log n)$."
    },
    {
      "id": "q29",
      "difficulty": 3,
      "skills": [
        "trace-tri-fusion"
      ],
      "title": "Trace du tri fusion",
      "statement": "On applique le tri fusion à la liste\n`[5, 2, 8, 3]`. Quelles sont les listes\npassées à la fusion finale (la dernière\nétape, qui produit la liste triée\ncomplète) ?",
      "options": [
        {
          "text": "`[2, 3, 5, 8]` et `[]`\n",
          "correct": false,
          "feedback": "Erreur : la fusion combine deux\nmoitiés non vides. Une moitié vide\nsignifierait qu'on a fait un seul tri\nrécursif suivi d'une fusion sans\ncontrepartie, ce qui n'est pas le\ntri fusion.\n"
        },
        {
          "text": "`[5]`, `[2]`, `[8]`, `[3]`\n",
          "correct": false,
          "feedback": "Erreur : ce sont les listes singletons\nobtenues à la fin du découpage. La\nfusion finale ne combine que **deux**\nlistes, pas quatre. Quatre singletons\nimpliqueraient deux fusions\nintermédiaires avant la fusion finale.\n"
        },
        {
          "text": "`[5, 2]` et `[8, 3]`\n",
          "correct": false,
          "feedback": "Erreur : ce sont les deux moitiés\nobtenues après le **premier** découpage,\nmais avant les tris récursifs. À la\nfusion finale, ces moitiés ont déjà\nété triées et sont devenues `[2, 5]`\net `[3, 8]`.\n"
        },
        {
          "text": "`[2, 5]` et `[3, 8]`\n",
          "correct": true,
          "feedback": "Bonne réponse : on découpe d'abord en\n`[5, 2]` et `[8, 3]`. On trie\nrécursivement chaque moitié : `[5, 2]`\ndevient `[2, 5]` après fusion de `[5]`\net `[2]` ; `[8, 3]` devient `[3, 8]`\naprès fusion de `[8]` et `[3]`. La\nfusion finale combine `[2, 5]` et\n`[3, 8]` pour produire `[2, 3, 5, 8]`.\n"
        }
      ],
      "explanation": "Schéma global du tri fusion : une phase\ndescendante de découpage récursif (jusqu'aux\nsingletons), suivie d'une phase remontante\nde fusions successives. Pour $n = 4$, la\nstructure d'appels forme un arbre binaire\ncomplet de hauteur $\\log_2 4 = 2$. À chaque\nniveau, le coût total des fusions est en\n$O(n)$, d'où la complexité globale en\n$O(n \\log n)$."
    },
    {
      "id": "q30",
      "difficulty": 3,
      "skills": [
        "code-fusion"
      ],
      "title": "Code de la fonction de fusion",
      "statement": "Quelle fonction Python implémente\ncorrectement la **fusion** de deux listes\ndéjà triées en une seule liste triée ?",
      "options": [
        {
          "text": "```\ndef fusion(a, b):\n    return a + b\n```\n",
          "correct": false,
          "feedback": "Erreur : la simple concaténation ne\ntrie pas. Si `a = [1, 4, 7]` et `b =\n[2, 3, 5]`, on obtiendrait\n`[1, 4, 7, 2, 3, 5]`, qui n'est pas\ntrié. Il faut entrelacer les deux\nlistes par comparaisons.\n"
        },
        {
          "text": "```\ndef fusion(a, b):\n    return sorted(a + b)\n```\n",
          "correct": false,
          "feedback": "Cette version fonctionne mais\nn'illustre pas l'algorithme : on délègue\nau tri intégré, qui ne tire pas parti\ndu fait que `a` et `b` sont déjà\ntriées. Complexité : $O((n+m) \\log(n+m))$\nau lieu de $O(n + m)$.\n"
        },
        {
          "text": "```\ndef fusion(a, b):\n    resultat = []\n    for x in a:\n        for y in b:\n            if x <= y:\n                resultat.append(x)\n            else:\n                resultat.append(y)\n    return resultat\n```\n",
          "correct": false,
          "feedback": "Erreur : la double boucle imbriquée a\nune complexité $O(n \\cdot m)$ au lieu\nde $O(n + m)$. De plus, on ajoute des\néléments en double (chaque élément de\n`a` est comparé à chaque élément de\n`b`, et chaque comparaison ajoute une\nvaleur). Le résultat n'est ni trié, ni\nde la bonne taille.\n"
        },
        {
          "text": "```\ndef fusion(a, b):\n    i, j = 0, 0\n    resultat = []\n    while i < len(a) and j < len(b):\n        if a[i] <= b[j]:\n            resultat.append(a[i])\n            i += 1\n        else:\n            resultat.append(b[j])\n            j += 1\n    resultat.extend(a[i:])\n    resultat.extend(b[j:])\n    return resultat\n```\n",
          "correct": true,
          "feedback": "Bonne réponse : on utilise deux indices\n`i` et `j` pour parcourir les deux\nlistes en parallèle. À chaque tour, on\najoute le plus petit des deux éléments\nde tête, et on avance l'indice\ncorrespondant. Quand l'une des listes\nest épuisée, on copie simplement le\nreste de l'autre. Complexité : $O(n + m)$\noù $n$ et $m$ sont les longueurs des\ndeux listes. Le `<=` (plutôt que `<`)\ndans la comparaison garantit la\nstabilité du tri.\n"
        }
      ],
      "explanation": "Cette fonction est le cœur du tri fusion :\nla qualité de l'algorithme global vient\nde l'efficacité linéaire de la fusion.\nVariante intéressante : implémenter la\nfusion **en place** dans la liste\nd'origine, ce qui économise de la\nmémoire. C'est cependant plus délicat à\ncoder et n'apporte pas de gain en\ncomplexité asymptotique."
    },
    {
      "id": "q31",
      "difficulty": 3,
      "skills": [
        "partition-tri-rapide"
      ],
      "title": "Code du partitionnement",
      "statement": "Dans le tri rapide, l'étape de\n**partitionnement** réorganise un tableau\nautour d'un pivot. Quel code Python\nimplémente correctement cette étape (avec\nle pivot pris comme dernier élément du\nsous-tableau, schéma de Lomuto) ?",
      "options": [
        {
          "text": "```\ndef partitionner(tab, debut, fin):\n    gauche = [x for x in tab if x <= tab[fin]]\n    droite = [x for x in tab if x > tab[fin]]\n    return gauche + droite\n```\n",
          "correct": false,
          "feedback": "Cette version fonctionne **logiquement**\n(elle produit une liste partitionnée),\nmais elle crée deux nouvelles listes,\nce qui contredit l'esprit du tri\nrapide qui est de trier **en place**\navec une mémoire $O(\\log n)$ pour la\npile. De plus, la signature ne renvoie\npas l'indice du pivot.\n"
        },
        {
          "text": "```\ndef partitionner(tab, debut, fin):\n    pivot = tab[fin]\n    i = debut - 1\n    for j in range(debut, fin):\n        if tab[j] <= pivot:\n            i += 1\n            tab[i], tab[j] = tab[j], tab[i]\n    tab[i + 1], tab[fin] = tab[fin], tab[i + 1]\n    return i + 1\n```\n",
          "correct": true,
          "feedback": "Bonne réponse : c'est le schéma de\nLomuto. L'indice `i` représente la\nfrontière entre les éléments « plus\npetits que le pivot » (avant `i`) et\nceux « plus grands » (entre `i` et\n`j`). À la fin, on place le pivot à sa\nposition définitive (entre les deux\nzones), et la fonction renvoie cette\nposition. Complexité : $O(n)$ pour le\npartitionnement seul, $O(n \\log n)$ en\nmoyenne pour le tri complet.\n"
        },
        {
          "text": "```\ndef partitionner(tab, debut, fin):\n    return tab[fin]\n```\n",
          "correct": false,
          "feedback": "Erreur : ce code ne fait que renvoyer\nle pivot sans réorganiser le tableau.\nLe partitionnement doit déplacer\nactivement les éléments selon leur\ncomparaison au pivot.\n"
        },
        {
          "text": "```\ndef partitionner(tab, debut, fin):\n    tab.sort()\n    return len(tab) // 2\n```\n",
          "correct": false,
          "feedback": "Erreur : trier le tableau entier\ncourt-circuite tout l'intérêt du tri\nrapide. Et le partitionnement ne doit\npas trier mais réarranger autour du\npivot.\n"
        }
      ],
      "explanation": "Le schéma de Lomuto est le plus simple à\nretenir, mais celui de **Hoare** (avec\ndeux indices qui se rapprochent l'un de\nl'autre) est en général un peu plus\nefficace en pratique. Le choix du pivot\nest crucial : avec un mauvais pivot\n(extremum), la complexité dégénère à\n$O(n^2)$. Stratégies courantes : pivot\naléatoire, médiane de trois, etc."
    }
  ]
}