Cod sursa(job #466798)

Utilizator savimSerban Andrei Stan savim Data 27 iunie 2010 14:54:47
Problema Numarare Scor 10
Compilator cpp Status done
Runda Stelele Informaticii 2010, clasele X-XII, Ziua 1 Marime 2.67 kb
#include <stdio.h>
#include <algorithm>

using namespace std;

#define MAX_N 100010

long long sol;
int st, n;
int A[MAX_N];
int diff[MAX_N];
int p2[MAX_N];
int rmq_min[17][MAX_N], rmq_max[17][MAX_N];

void expand(int i) {
	while (st - 1 >= 1 && i + 1 + (i - st) + 1 <= n && A[st - 1] + A[i + 1 + (i - st) + 1] == A[i] + A[i + 1])
		st--;
}

inline int query_min(int st, int dr) {
	int dist = dr - st + 1;
	return min(rmq_min[p2[dist]][st], rmq_min[p2[dist]][dr - (1 << p2[dist]) + 1]);
}

inline int query_max(int st, int dr) {
	int dist = dr - st + 1;
	return max(rmq_max[p2[dist]][st], rmq_max[p2[dist]][dr - (1 << p2[dist]) + 1]);
}

void solve(int dec) {
	st = 1;	sol++;
	for (int i = 2; i <= n / 2 - dec; i++) {
		if (st != i - 1) {
			int r_min = query_min(i + 2, i + 2 + (i - st - 1));
			int r_max = query_max(i + 2, i + 2 + (i - st - 1));

			if (r_min != r_max) {
            	if (A[i - 1] + A[i + 2] != A[i] + A[i + 1])
					st = i;
				else {
                	int left = st, right = i, mid = 0, rez = i;
					while (left + 1 < right) {
                    	mid = (left + right) / 2;

						r_min = query_min(i + 2, i + 2 + (i - mid - 1));
						r_max = query_max(i + 2, i + 2 + (i - mid - 1));
			
						if (r_min == r_max) {
                        	rez = min(rez, mid);
							right = mid;
						}
						else
							left = mid;
					}

					st = rez;
				}
			}
		}
		else
			st = i;

		expand(i);
		sol = sol + (i - st + 1);
	}	
}

int main() {

	freopen("numarare.in", "r", stdin);
	freopen("numarare.out", "w", stdout);

	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		scanf("%d", &A[i]);

	for (int i = 3; i <= n; i++) {
		diff[i] = A[i] - A[i - 2];

    	rmq_min[0][i] = rmq_max[0][i] = diff[i];
	}

	for (int i = 0; i < 17; i++)
		p2[1 << i] = i;
	for (int i = 2; i < n; i++)               
		if (p2[i + 1] == 0)
			p2[i + 1] = p2[i];

	for (int i = 1; (1 << i) <= n; i++)
		for (int j = 1; j + (1 << i) - 1 <= n; j++) {
			int right = j + (1 << i) - 1;

			rmq_min[i][j] = min(rmq_min[i - 1][j], rmq_min[i - 1][right - (1 << (i - 1)) + 1]);
			rmq_max[i][j] = max(rmq_max[i - 1][j], rmq_max[i - 1][right - (1 << (i - 1)) + 1]);
		}

	solve(0);

	for (int i = 1; i <= n / 2; i++)
		swap(A[i], A[n + 1 - i]);

	for (int i = 3; i <= n; i++)
		rmq_min[0][i] = rmq_max[0][i] = A[i] - A[i - 2];

	for (int i = 1; (1 << i) <= n; i++)
        for (int j = 1; j + (1 << i) - 1 <= n; j++) {
            int right = j + (1 << i) - 1;

            rmq_min[i][j] = min(rmq_min[i - 1][j], rmq_min[i - 1][right - (1 << (i - 1)) + 1]);
            rmq_max[i][j] = max(rmq_max[i - 1][j], rmq_max[i - 1][right - (1 << (i - 1)) + 1]);
        }

	if (n % 2 == 0)
		solve(1);
	else
		solve(0);

	printf("%lld\n", sol);

	return 0;
}