Cod sursa(job #1463897)

Utilizator bciobanuBogdan Ciobanu bciobanu Data 21 iulie 2015 19:37:31
Problema Secventa 5 Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.17 kb
#include <stdio.h>
#include <string.h>

#define MAX_N (1 << 20)
#define HASHSIZE 666013
#define h(X) ((X) - (X) / HASHSIZE * HASHSIZE)
#define NIL -1

typedef struct {
  unsigned key;
  int cnt;
  int next;
} cell;

cell l[MAX_N];      // buffer prealocat
int buffPtr;        // ultima pozitie libera din buffer

int st[MAX_N];      // stiva de pozitii libere
int s;              // numarul de elemente din liste

int hash[HASHSIZE]; // capetele listelor, initializate cu NIL

unsigned v[MAX_N];  // sirul dat
int n;              // lungimea sirului dat

static inline int hashRemove(const unsigned &q) {
  int hq = h(q);

  if (l[hash[hq]].key == q) {   // daca se afla la capatul listei
    l[hash[hq]].cnt--;
    if (!l[hash[hq]].cnt) {
      st[s++] = hash[hq];
      hash[hq] = l[hash[hq]].next;
      return NIL;
    }
  } else {
    int i = hash[hq];

    while (l[i].next != NIL && l[l[i].next].key != q) {
      i = l[i].next;
    }
    if (l[i].next != NIL) {
      l[l[i].next].cnt--;
      if (!l[l[i].next].cnt) {
        st[s++] = l[i].next;            // retin in stiva de pozitii o noua pozitie libera
        l[i].next = l[l[i].next].next;  // sterg nodul din lista
        return NIL;
      }
    }
  }
  return 0;
}

static inline int hashCount(const unsigned &q) {
  int i = hash[h(q)];

  while (i != NIL && l[i].key != q) {
    i = l[i].next;
  }

  if (i != NIL) {
    return l[i].cnt;
  }
  return 0;
}

static inline void hashInsert(const unsigned &q) {
  int i = hash[h(q)];

  while (i != NIL && l[i].key != q) {
    i = l[i].next;
  }
  if (i != NIL) {
    l[i].cnt++;
  } else {
    i = s ? st[--s] : buffPtr++;

    l[i].key = q;
    l[i].cnt = 1;
    l[i].next = hash[h(q)];
    hash[h(q)] = i;
  }
}

static unsigned long long cntSecv(int x) {
  int start;
  int nDist;
  unsigned long long nSecv;

  // initializare hash
  memset(hash, NIL, sizeof(hash));  // capetele listelor pe NIL
  buffPtr = 0;                      // numarul de pozitii folosite in buffer
  s = 0;                            // numarul de pozitii eliberate prin stergere

  // initializare variabile
  start = 0;    // secventa curenta este [start, i]
  nDist = 0;    // numarul de elemente distincte in secventa curenta
  nSecv = 0ULL; // numarul de secvente in care numarul de nr. distincte <= x

  for (int i = 0; i < n; i++) {
    if (!hashCount(v[i])) {       // daca apare pentru prima data
      nDist++;                    // cresc numarul de numere distincte
    }
    hashInsert(v[i]);
    while (nDist > x) {                // daca numarul de numere distincte este prea mare
      nDist += hashRemove(v[start++]); // scad din numarul de numere distincte daca aceasta nu mai exista in hash
    }
    nSecv += (i - start + 1);          // toate secventele din interiorul [start, i] au numar de numere distincte <= x
  }
  return nSecv;
}

int main(void) {
  FILE *f = fopen("secv5.in", "r");
  int lo, hi;

  fscanf(f, "%d%d%d", &n, &lo, &hi);

  for (int i = 0; i < n; i++) {
    fscanf(f, "%u", &v[i]);
  }
  fclose(f);

  f = fopen("secv5.out", "w");
  fprintf(f, "%llu\n", cntSecv(hi) - cntSecv(lo - 1)); // din numarul secventelor cu nr. distincte <= hi scad numarul secventelor cu nr. distincte < lo
  fclose(f);
  return 0;
}