Problem:
Score : 700 points

Problem Statement

N cells are arranged in a row.
Some of them may contain tokens.
You are given a string s that consists of 0s and 1s.
If the i-th character of s is 1, the i-th cell (from left) contains a token.
Otherwise, it doesn't contain a token.

Snuke wants to perform the following operation as many times as possible.
In each operation, he chooses three consecutive cells.
Let's call the cells X, Y, Z from left to right.
In order for the operation to be valid, both X and Z must contain tokens and Y must not contain a token.
Then, he removes these two tokens and puts a new token on Y.

How many operations can he perform if he performs operations in the optimal way?

Constraints

1 \leq N \leq 500,000

|s| = N

Each character in s is either 0 or 1.

Input

Input is given from Standard Input in the following format:

N
s

Output

Print the answer.

Sample Input 1

7
1010101

Sample Output 1

2

For example, he can perform two operations in the following way:

Perform an operation on the last three cells. Now the string that represents tokens becomes 1010010.

Perform an operation on the first three cells. Now the string that represents tokens becomes 0100010.

Note that the choice of operations matters.
For example, if he chooses three cells in the middle first, he can perform no more operations.

Sample Input 2

50
10101000010011011110001001111110000101010111100110

Sample Output 2

10

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

//#pragma warning disable
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System;
using System.Numerics;
using System.Threading.Tasks;
using static System.Math;
using static System.Console;
class Z { static void Main() => new K(); }
class K
{
	int F() => int.Parse(ReadLine());
	long FL() => long.Parse(ReadLine());
	int[] G() => ReadLine().Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray();
	long[] GL() => ReadLine().Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries).Select(long.Parse).ToArray();
	public const int MOD = 1000000007;
	public K()
	{
		//SetOut(new StreamWriter(OpenStandardOutput()) { AutoFlush = false });
		Solve();
		//Out.Flush();
	}
	int N;
	List<bool> s;
	void Solve()
	{
		N = F();
		s = Console.ReadLine().Select(x => x == '1').ToList();
		s.Add(false);
		s.Add(false);
		N += 2;
		var l = 0;
		var ans = 0;
		while (true)
		{
			while (l < N && !s[l]) l++;
			if (l >= N) break;
			int r = l + 1;
			while (s[r] || s[r + 1]) r++;
			ans += Solve(l, r);
			l = r;
		}
		WriteLine(ans);
	}
	int Solve(int l, int r)
	{
		var x = new List<int>{ 0 };
		var i = 0;
		while (l < r)
		{
			if (s[l++]) x[i]++;
			else
			{
				x.Add(0);
				i++;
			}
		}
		if (i == 0) return 0;
		//Console.WriteLine(string.Join(", ", x));
		var a = DP(x, x.Count);
		//Console.WriteLine(a);
		return a;
	}
	static int L0(int a, int b) => a;
	static int L1(int a, int b) => a - 1;
	static int L2(int a, int b) => 1;
	static int L3(int a, int b) => 1;
	static int L4(int a, int b) => 1;
	static int L5(int a, int b) => 0;
	static int R0(int a, int b) => 1;
	static int R1(int a, int b) => 1;
	static int R2(int a, int b) => b;
	static int R3(int a, int b) => b - 1;
	static int R4(int a, int b) => 1;
	static int R5(int a, int b) => 0;
	static bool P0(int a, int b) => a > 1;
	static bool P1(int a, int b) => a > 2;
	static bool P2(int a, int b) => b > 1;
	static bool P3(int a, int b) => b > 2;
	static bool P4(int a, int b) => true;
	static bool P5(int a, int b) => true;
	static Func<int, int, int>[] L = new Func<int, int, int>[]{L0, L1, L2, L3, L4, L5};
	static Func<int, int, int>[] R = new Func<int, int, int>[]{R0, R1, R2, R3, R4, R5};
	static Func<int, int, bool>[] P = new Func<int, int, bool>[]{P0, P1, P2, P3, P4, P5};
	static int DP(List<int> x, int n)
	{
		if (n <= 1) return 0;
		if (n == 2) return x.Max();
		var dp = new int[n - 1, 6];
		dp[0, 0] = x[0];
		dp[0, 1] = x[0] - 1;
		dp[0, 2] = x[1];
		dp[0, 3] = x[1] - 1;
		dp[0, 4] = 1;
		for (var i = 1; i < n - 1; i++)
		{
			for (var j = 0; j < 6; j++)
				for (var k = 0; k < 6; k++)
				{
					if (!P[j](x[i - 1], x[i]) || !P[k](x[i], x[i + 1]) || R[j](x[i - 1], x[i]) + L[k](x[i], x[i + 1]) > x[i]) continue;
					dp[i, k] = Max(dp[i, k], dp[i - 1, j] + Max(L[k](x[i], x[i + 1]), R[k](x[i], x[i + 1])));
				}
			/*for (var j = 0; j < 6; j++) dp[i, j] = dp[i - 1, 5];
			for (var j = 0; j < 5; j++) dp[i, 5] = Max(dp[i, 5], dp[i - 1, j]);
			if (x[i + 1] > 1) dp[i, 2] = Max(dp[i, 2], dp[i - 1, 3] + x[i + 1]);
			if (x[i + 1] > 2) dp[i, 3] = Max(dp[i, 3], dp[i - 1, 3] + x[i + 1] - 1);
			dp[i, 4] = Max(dp[i, 4], dp[i - 1, 3] + 1);
			if (x[i] - 1 > 1) dp[i, 1] = Max(dp[i, 1], dp[i - 1, 0] + x[i] - 1);
			dp[i, 5] = Max(dp[i, 5], dp[i - 1, 2]);
			dp[i, 0] = dp[i - 1, 0] + x[i] - 1;
			dp[i, 0] = Max(dp[i, 0], dp[i - 1, 1]);
			dp[i, 0] = Max(dp[i, 0], dp[i - 1, 2]);
			dp[i, 1] = dp[i - 1, 0] + (x[i] > 1 ? x[i + 1] : 0);
			dp[i, 1] = Max(dp[i, 1], dp[i - 1, 1] + (x[i] > 1 ? x[i + 1] - 1 : 0));
			dp[i, 1] = Max(dp[i, 1], dp[i - 1, 2] + x[i + 1]);
			dp[i, 2] = Max(dp[i - 1, 0], dp[i - 1, 1]);
			dp[i, 2] = Max(dp[i, 2], dp[i - 1, 2]);*/
		}
		/*for (var i = 0; i < n - 1; i++)
		{
			Console.WriteLine($"dp[{i}, 0] = {dp[i, 0]}");
			Console.WriteLine($"dp[{i}, 1] = {dp[i, 1]}");
			Console.WriteLine($"dp[{i}, 2] = {dp[i, 2]}");
		}*/
		var m = 0;
		for (var i = 0; i < 6; i++) m = Max(m, dp[n - 2, i]);
		return m;
	}
}