Recentemente, ho appreso Mo's algorithm per la scomposizione quadrata delle query al fine di accelerare le soluzioni a determinati problemi.Algoritmo di Mo per calcolare "potenza" dell'array
Per praticare l'implementazione, ho cercato di risolvere D. Powerful array (un problema di contest passato su Codeforces) utilizzando questa idea. Il problema è il seguente:
Si dispone di un array con numeri interi .
Prendere in considerazione un sottoarray arbitrario . Definire come il numero di occorrenze di un numero intero in questo sottoarray. Il potere di un sottoarray è definito come la somma di per tutti gli interi (notare che c'è solo un numero positivo di termini per i quali questo non è zero).
rispondere alle domande . In ogni query, dati due numeri interi e , calcolare la potenza di .
Contiene:
utilizzando l'algoritmo di Mo, ho scritto il codice che risolve questo problema non in linea in . Sono sicuro che questo problema può essere risolto utilizzando questo algoritmo e la complessità del tempo, poiché ho ispezionato il codice accettato da altri e usano anche un algoritmo simile.
Il mio codice, tuttavia, gets a time limit exceeded verdict.
Di seguito è il codice che ho scritto:
#include <ios>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <utility>
#include <map>
int sqt;
long long int ans = 0;
long long int arr[200005] = {};
long long int cnt[1000005] = {};
long long int tans[200005] = {};
struct el
{
int l, r, in;
};
bool cmp(const el &x, const el &y)
{
if (x.l/sqt != y.l/sqt)
return x.l/sqt < y.l/sqt;
return x.r < y.r;
}
el qr[200005];
int main()
{
std::ios_base::sync_with_stdio(false);
std::cin.tie(NULL);
std::cout.tie(NULL);
int n, q, a, b;
std::cin >> n >> q;
sqt = sqrt((double)(n))+27;
for (int i = 0; i < n; i++)
std::cin >> arr[i];
for (int i = 0; i < q; i++)
{
std::cin >> a >> b;
a--; b--;
qr[i].l = a;
qr[i].r = b;
qr[i].in = i;
}
std::sort(qr, qr+q, cmp);
int li = 0; //left iterator
int ri = 0; //right iterator
ans = arr[0];
cnt[arr[0]]++;
for (int i = 0; i < q; i++)
{
while (li < qr[i].l)
{
ans -= cnt[arr[li]]*cnt[arr[li]]*arr[li];
cnt[arr[li]]--;
ans += cnt[arr[li]]*cnt[arr[li]]*arr[li];
li++;
}
while (li > qr[i].l)
{
li--;
ans -= cnt[arr[li]]*cnt[arr[li]]*arr[li];
cnt[arr[li]]++;
ans += cnt[arr[li]]*cnt[arr[li]]*arr[li];
}
while (ri < qr[i].r)
{
ri++;
ans -= cnt[arr[ri]]*cnt[arr[ri]]*arr[ri];
cnt[arr[ri]]++;
ans += cnt[arr[ri]]*cnt[arr[ri]]*arr[ri];
}
while (ri > qr[i].r)
{
ans -= cnt[arr[ri]]*cnt[arr[ri]]*arr[ri];
cnt[arr[ri]]--;
ans += cnt[arr[ri]]*cnt[arr[ri]]*arr[ri];
ri--;
}
tans[qr[i].in] = ans;
}
for (int i = 0; i < q; i++)
std::cout << tans[i] << '\n';
}
si può suggerire qualsiasi (anche una o forse asintotico) il miglioramento non asintotico in grado di accelerare il programma abbastanza per passare il limite di tempo?
ho già provato le seguenti cose, inutilmente:
- Utilizzando un vettore invece che una matrice.
- Utilizzo di due coppie nidificate anziché struct.
- Utilizzare solo una coppia e quindi utilizzare una mappa per provare a ripristinare l'ordine corretto di risposte.
- Aggiunta di alcune varie costanti a
sqt
(come nel codice sopra). - Sovraccarico dell'operatore di confronto < all'interno della struttura
el
.
Mi sento come se mi mancasse qualcosa di importante, dal momento che gli altri codici che ho ispezionato sembrano passare il limite di tempo con un po 'di margine di manovra (circa mezzo secondo). Tuttavia, sembrano utilizzare lo stesso algoritmo del mio codice.
Qualsiasi aiuto sarebbe molto apprezzato!
Si definisce la potenza di un sottoarray in termini di a, l, r e s, ma ogni query ha solo a, l e r specificati. È la somma presa su tutti s? – jbapple
Sì, è la somma su tutte le s. Ho aggiunto questo alla domanda, grazie per aver chiarito! –
Il link di descrizione che hai fornito http://blog.anudeep2011.com/mos-algorithm/ dice in basso, "Nota: quel codice darà TLE in fase di invio, fornirà AC se viene aggiunto I/O veloce. I/O per mantenere pulito il codice. " Sembra che l'IO potrebbe essere il problema, dal momento che i cin/cout non sono molto veloci. Suggerisco di controllare il tempo di IO rispetto al tempo di elaborazione e vedere se l'IO potrebbe essere la causa del limite di tempo superato. –