Pagini recente » Borderou de evaluare (job #1359969) | Borderou de evaluare (job #315089) | Cod sursa (job #1660590) | Cod sursa (job #287275) | Cod sursa (job #1463905)
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX_N (1 << 20)
#define HASHSIZE 666013
#define h(X) ((X) - (X) / HASHSIZE * HASHSIZE)
#define NIL -1
typedef struct {
unsigned key;
unsigned 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 unsigned readUint(FILE *f) {
char c;
unsigned q;
do {
c = fgetc_unlocked(f);
} while (!isdigit(c));
q = 0;
do {
q = (q << 1) + (q << 3) + (c - '0');
c = fgetc_unlocked(f);
} while (isdigit(c));
return q;
}
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--; // scad nr. aparitii
if (!l[hash[hq]].cnt) { // daca numarul de aparitii e 0, atunci tb stearsa din hash
st[s++] = hash[hq]; // retin in stiva pozitia libera
hash[hq] = l[hash[hq]].next; // sterg nodul din lista
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--; // scad numarul de aparitii
if (!l[l[i].next].cnt) { // daca numarul de aparitii e 0, inseamna ca trebuie stearsa din hash
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) { // apare in hash
return l[i].cnt;
}
return 0; // nu apare in hash
}
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) { // daca exista deja in hash cresc numarul de aparitii
l[i].cnt++;
} else { // altfel, o adaug in hash
i = s ? st[--s] : buffPtr++; // verific daca pot refolosi pozitii
l[i].key = q; // lista in stil stiva
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++) {
nDist += !hashCount(v[i]); // daca nu exista in hash, atunci 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++) {
v[i] = readUint(f);
}
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;
}