F5 : meilleure période en un seul parcours (O(J³) → O(J))

La triple boucle recalculait la somme de chaque période (i, j) :
J(J+1)(J+2)/6 = 167 millions d'additions pour 1 000 jours. Avec les
sommes préfixes, la meilleure période finissant au jour j commence
juste après le plus petit préfixe vu jusque-là : un seul parcours
suffit. En gardant le premier minimum et en ne remplaçant le meilleur
que s'il est strictement dépassé, on retrouve la même période que
l'original en cas d'égalité (vérifié sur 200 000 tableaux aléatoires).

Temps (-O2) : 0,25 s → 0,10 s. Empreinte inchangée (ff68d260a7a58441).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-21 10:55:53 +02:00
parent c84ff59ec3
commit 922703999f
+17 -10
View File
@@ -127,21 +127,28 @@ void total_par_jour(const Transaction *t, int n, long *totaux)
}
/* F5 : période de jours consécutifs dont la somme des soldes est maximale */
/* Avec prefixe(j) = totaux[0] + ... + totaux[j-1], la somme des jours i à j
* vaut prefixe(j+1) - prefixe(i). Pour chaque fin j, le meilleur début est
* donc l'indice du plus petit prefixe(i), i <= j. On garde le premier minimum
* et on ne remplace le meilleur que s'il est strictement dépassé : on obtient
* la même période que la triple boucle d'origine, même en cas d'égalité. */
long meilleure_periode(const long *totaux, int nb_jours, int *debut, int *fin)
{
long meilleur = totaux[0];
long prefixe = 0, prefixe_min = 0;
int debut_min = 0;
*debut = 0;
*fin = 0;
for (int i = 0; i < nb_jours; i++) {
for (int j = i; j < nb_jours; j++) {
long somme = 0;
for (int k = i; k <= j; k++)
somme += totaux[k];
if (somme > meilleur) {
meilleur = somme;
*debut = i;
*fin = j;
}
for (int j = 0; j < nb_jours; j++) {
if (prefixe < prefixe_min) { /* prefixe vaut ici prefixe(j) */
prefixe_min = prefixe;
debut_min = j;
}
prefixe += totaux[j]; /* prefixe vaut maintenant prefixe(j+1) */
if (prefixe - prefixe_min > meilleur) {
meilleur = prefixe - prefixe_min;
*debut = debut_min;
*fin = j;
}
}
return meilleur;