Аналіз алгоритму
Кожен запит можна виконувати за допомогою циклу за час . Існує запитів, довжина масиву складає . При лінійному часі виконання запиту нам потрібно не більше операцій, що дасть Time Limit.
Розглянемо часткові суми масиву :. . .
Обчислити значення можна в лінійному масиві за час .
Далі помітимо, що
Таким чином відповісти на запит можна за , тобто за константний час.
Приклад
Обчислимо суму для наведеного в умові прикладу.
Маємо:
Реалізація алгоритму
Оголосимо два робочих одновимірних масиви.
#define MAX 1000001 int a[MAX], s[MAX];
Читаємо вхідний набір чисел у масив a
, обчислюємо часткові суми у масиві s
.
scanf("%d",&n); s[0] = 0; for(i = 1; i <= n; i++) { scanf("%d",&a[i]); s[i] = s[i-1] + a[i]; }
Обробляємо запитів.
scanf("%d",&m); for(i = 0; i < m; i++) { scanf("%d %d",&b,&c); printf("%d\n",s[c] - s[b-1]); }
Реалізація алгоритму – SQRT декомпозиція - TLE
#include <cstdio> #include <cmath> #include <vector> using namespace std; int i, n, m, len, x, y; vector<int> a, b; int q(int l, int r) { int i, sum = 0; int c_l = l / len, c_r = r / len; if (c_l == c_r) for (i = l; i <= r; i++) sum += a[i]; else { for (i = l; i <= (c_l + 1)*len - 1; i++) sum += a[i]; for (i = c_l + 1; i <= c_r - 1; i++) sum += b[i]; for (i = c_r * len; i <= r; i++) sum += a[i]; } return sum; } int main(void) { scanf("%d", &n); a.resize(n); for (i = 0; i < n; i++) scanf("%d", &a[i]); len = sqrt(n) + 1; b.resize(len); for (i = 0; i < n; i++) b[i / len] += a[i]; scanf("%d", &m); for (i = 0; i < m; i++) { scanf("%d %d", &x, &y); printf("%d\n", q(x - 1, y - 1)); } return 0; }
Реалізація алгоритму – запит за лінійний час - TLE
#include <stdio.h> #define MAX 1000001 int i, j, n, m, b, c, s; int a[MAX]; int main(void) { scanf("%d", &n); for (i = 1; i <= n; i++) scanf("%d", &a[i]); scanf("%d", &m); for (i = 0; i < m; i++) { scanf("%d %d", &b, &c); s = 0; for (j = b; j <= c; j++) s = s + a[j]; printf("%d\n", s); } return 0; }