2016-04-04 13 views
5

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 narray.

Prendere in considerazione un sottoarray arbitrario subarray. Definire Ks come il numero di occorrenze di un numero intero s in questo sottoarray. Il potere di un sottoarray è definito come la somma di Ks*Ks*s per tutti gli interi s (notare che c'è solo un numero positivo di termini per i quali questo non è zero).

rispondere alle domande q. In ogni query, dati due numeri interi l e r, calcolare la potenza di subarray.

Contiene:

limits1
limits2
limits3

utilizzando l'algoritmo di Mo, ho scritto il codice che risolve questo problema non in linea in complexity. 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:

  1. Utilizzando un vettore invece che una matrice.
  2. Utilizzo di due coppie nidificate anziché struct.
  3. Utilizzare solo una coppia e quindi utilizzare una mappa per provare a ripristinare l'ordine corretto di risposte.
  4. Aggiunta di alcune varie costanti a sqt (come 27 nel codice sopra).
  5. 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!

+0

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

+0

Sì, è la somma su tutte le s. Ho aggiunto questo alla domanda, grazie per aver chiarito! –

+1

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. –

risposta

1

Si potrebbe forza-ridurre

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++; 
    } 

a

while (li < qr[i].l) 
    { 
     ans -= (2*cnt[arr[li]]-1)*arr[li]; 
     cnt[arr[li]]--; 
     li++; 
    } 

e allo stesso modo per gli altri.

+0

Sembra che la modifica consenta di accettare il mio codice, anche se a malapena (4960 ms). –

Problemi correlati