Problem:
Score : 600 points

Problem Statement

Given is an integer sequence A_1, ..., A_N of length N.

We will choose exactly \left\lfloor \frac{N}{2} \right\rfloor elements from this sequence so that no two adjacent elements are chosen.

Find the maximum possible sum of the chosen elements.

Here \lfloor x \rfloor denotes the greatest integer not greater than x.

Constraints

2 \leq N \leq 2\times 10^5

|A_i|\leq 10^9

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N
A_1 ... A_N

Output

Print the maximum possible sum of the chosen elements.

Sample Input 1

6
1 2 3 4 5 6

Sample Output 1

12

Choosing 2, 4, and 6 makes the sum 12, which is the maximum possible value.

Sample Input 2

5
-1000 -100 -10 0 10

Sample Output 2

0

Choosing -10 and 10 makes the sum 0, which is the maximum possible value.

Sample Input 3

10
1000000000 1000000000 1000000000 1000000000 1000000000 1000000000 1000000000 1000000000 1000000000 1000000000

Sample Output 3

5000000000

Watch out for overflow.

Sample Input 4

27
18 -28 18 28 -45 90 -45 23 -53 60 28 -74 -71 35 -26 -62 49 -77 57 24 -70 -93 69 -99 59 57 -49

Sample Output 4

295

Solution in C++ (GCC 9.2.1) (judge verdict: Runtime Error)

#include <iostream>
#include <vector>
#include <string>
#include <stdio.h>
#include<limits.h>
#include<algorithm>
#include<queue>
#include<set>
#include<math.h>
#include<random>

#define lli long long int
#define MOD 1000000007

using namespace std;

long long int modpow(long long int a, long long int n) {
	if (n == 0)return 1;
	if (n == 1)return (a % MOD);

	long long int hanbun = n / 2;
	long long int amari = n % 2;

	long long int ans = (a * a) % MOD;
	ans = modpow(ans, hanbun);

	if (amari == 1)ans *= a;

	ans %= MOD;

	return ans;

}

long long int gcd(long long int a, long long int b) {
	if (a < b) {
		long long int tmp = a;
		a = b;
		b = tmp;
	}

	long long int amari = a % b;

	if (amari == 0)return b;

	return gcd(b, amari);
}

long long int lcm(long long int a, long long int b) {
	long long int ans = (a * b) % MOD;
	long long int wari = modpow(gcd(a, b), MOD - 2);
	ans = (ans * wari) % MOD;
	return ans;
}

long long int factElement[10000] = { 0 };

long long int factrial(int n) {

	if (factElement[n] != 0)return factElement[n];

	if (n == 0) {
		factElement[0] = 1;
		return factElement[n];
	}

	long long int ans = n * factrial(n - 1);
	factElement[n] = ans;
	return factElement[n];

}

struct SegmentTree {
private:
	int n;
	vector<long long int> node;
	int TANNI;

	long long int Func(long long int a, long long int b) {
		return min(a,b);
	}

public:
	//元配列ｖをセグメント木で表現する。
	SegmentTree(vector<long long int> v, long long int tanni) {
		//最下段のノード数は元配列のサイズ以上になる最小の2冪→これをｎとおく。
		//セグメント木全体で必要なノード数は2n-1個である。
		int sz = v.size();
		n = 1;
		while (n < sz)n *= 2;

		TANNI = tanni;
		node.resize(2 * n - 1, TANNI);

		//最下段に値を入れた後に、下の段から順番に値を入れる。
		//値を入れるには、自分の子の２値を参照すればよい。
		for (int i = 0; i < sz; i++)node[i + n - 1] = v[i];
		for (int i = n - 2; i >= 0; i--)node[i] = Func(node[2 * i + 1], node[2 * i + 2]);
	}

	void update(long long int x, long long int val) {
		//最下段のノードにアクセスする。
		x += (n - 1);

		//最下段のノードを更新したら、あとは親に上って更新していく。
		node[x] = val;

		while (x > 0) {
			x = (x - 1) / 2;
			node[x] = Func(node[2 * x + 1], node[2 * x + 2]);
		}
	}

	long long int getVal(int x) {
		x += (n - 1);
		return node[x];
	}

	long long int getAns(int a, int b, int k = 0, int l = 0, int r = -1) {
		//最初に呼び出された時の区間は[0,n)
		if (r < 0)r = n;

		//要求区間と対象区間が交わらない→単位元を返す。
		if (r <= a || b <= l) return TANNI;

		//要求区間が対象区間を完全に被覆する→対象区間を答えの計算に使う。
		if (a <= l && r <= b) return node[k];

		//要求区間が対象区間の一部を被覆→子をよびだす。
		//左の子をvl、右の子をvrとしている。
		//新しい対象区間は現在の対象区間を半分に割ったもの。
		int vl = getAns(a, b, 2 * k + 1, l, (l + r) / 2);
		int vr = getAns(a, b, 2 * k + 2, (l + r) / 2, r);
		return Func(vl, vr);


	}



};




lli ans = LLONG_MIN;


lli solve(vector<lli> info, int num) {

	lli ans = 0;

	if (num == 0)return 0;

	if (info.size() % 2 == 1 && (info.size() + 1) / 2 == num) {
		for (int i = 0; i < info.size(); i += 2) {
			ans += info[i];
		}

		return ans;
	}

	if (info.size() % 2 == 0) {
		if (num == info.size() / 2) {
			lli oddSum = 0;
			lli evenSum = 0;

			for (int i = 0; i < info.size(); i++) {
				if (i % 2 == 0)evenSum += info[i];
				else oddSum += info[i];
			}

			return max(evenSum, oddSum);
		}
		
	}
	
	int middle = info.size() / 2;

	vector<lli> hidari;
	vector<lli> migi;

	vector<lli> hidariTotyuu;
	vector<lli> migiTotyuu;

	for (int i = 0; i < info.size(); i++) {
		if (i < middle) {
			hidari.push_back(info[i]);

			if (i + 1 < middle) {
				hidariTotyuu.push_back(info[i]);
			}


		}
		else if (i > middle) {
			migi.push_back(info[i]);

			if (i - 1 > middle) {
				migiTotyuu.push_back(info[i]);
			}

		}
	}

	lli wkAns;

	int hidarikosuu = (hidari.size() + 1) / 2;
	int migikosuu = num - hidarikosuu;

	//真ん中を選ばないやつ
	while (true) {
		if (migikosuu > (migi.size() + 1) / 2)break;

		wkAns = solve(hidari, hidarikosuu) + solve(migi, migikosuu);

		ans = max(ans, wkAns);

		hidarikosuu--;
		migikosuu++;
	}

	//真ん中を選ぶやつ
	hidarikosuu = (hidari.size() + 1) / 2;
	migikosuu = num - hidarikosuu;

	migikosuu--;
	while (true) {
		if (migikosuu > (migi.size() + 1) / 2)break;

		wkAns = solve(hidariTotyuu, hidarikosuu) + solve(migiTotyuu, migikosuu) + info[middle];

		ans = max(ans, wkAns);
		hidarikosuu--;
		migikosuu++;
	}



	return ans;

	
}


int main()
{
	
	int n;
	cin >> n;


	lli sum = 0;
	vector<lli> a(n);
	for (auto& i : a) {
		cin >> i;
		sum += i;
	}

	//偶数要素ならこちら
	if (n % 2 == 0) {
		lli guusuuSum = 0;

		for (int i = 0; i < a.size(); i++) {
			if (i % 2 == 0) {
				guusuuSum += a[i];
			}
		}

		lli kisuuSum = sum - guusuuSum;

		ans = max(guusuuSum, kisuuSum);



	}
	else {

		lli youso = n / 2;

		lli wkSum = 0;
		vector<bool> choiceInfo(n, false);
		

		for (int i = 0; i < youso; i++) {
			choiceInfo[2 * i] = true;
			wkSum += a[2 * i];
		}

		ans = solve(a, youso);

		
	









	}

	cout << ans << endl;


	return 0;

}