#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <array>
#include <stdint.h>
#include <set>
#include <unordered_map>
#include <map>
#include <bitset>
#include <string>
#include <cmath>
#include <queue>
#include <iterator>
#include <xutility>
#include <iomanip>
#include <numeric>
//#include "dmSegmentTree.hpp"
#include <xstddef>
#include <random>
#include <functional>

using namespace std;

#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define forn(i, n) for(int i = 0; i < int(n); i++)

template <class T>
vector<T> ReadVec(const int count)
{
	vector<T> res(count);
	forn(i, count)
	{
		std::cin >> res[i];
	}
	return res;
}

template <class T>
void PrintVecOneLine(const vector<T>& src)
{
	forn(i, src.size())
	{
		std::cout << src[i];
		if (i + 1 != src.size())
			std::cout << " ";
	}
	std::cout << "\n";
}

template <class T>
void PrintVecManyLine(const vector<T>& src)
{
	forn(i, src.size())
	{
		std::cout << src[i] << "\n";
	}
}

std::vector<std::vector<int>> BuildGraph(int n,int m, bool oriented, int inc = 1)
{
	std::vector<std::vector<int>> res(n);
	forn(i, m)
	{
		int a, b;
		std::cin >> a >> b;
		res[a - inc].push_back(b - inc);
		if (oriented)
			continue;
		res[b - inc].push_back(a - inc);
	}
	return res;
}

std::vector<std::vector<int>> BuildGraph(
	int n,int m, bool oriented, std::vector<int64_t>& weight, int inc = 1)
{
	std::vector<std::vector<int>> res(n);
	weight.resize(m);
	forn(i, m)
	{
		int a, b;
		std::cin >> a >> b >> weight[i];
		res[a - inc].push_back(b - inc);
		if (oriented)
			continue;
		res[b - inc].push_back(a - inc);
	}
	return res;
}

//int64_t inf = std::numeric_limits<int64_t>::max();

//#define HOME
// BABB A
// BA BABB B
// (a^2 + b^2) - 2ab== (a + b)^2
// sum = a^2 + b^2 + c^2

struct comp
{
	bool operator()(const std::pair<int, int>& a, const std::pair<int, int>& b) const
	{
		return a.first < b.first;
	}
};
int main()
{
#ifdef HOME
	freopen("input.txt", "r", stdin);
#else
	std::ios_base::sync_with_stdio(0); std::cin.tie(0); std::cout.tie(0);
	std::cout.setf(std::ios::fixed); std::cout.precision(20);
#endif
	int n;
	cin >> n;
	string s;
	cin >> s;
	int count = 0;
	int fIndx = n;
	std::vector<int64_t> sum(n, 0);
	std::vector<int64_t> ariph(n, 0);

	std::set<std::pair<int, int>, comp> maxInt;
	int64_t res = 0;
	for (int i = 1; i < n; ++i)
	{
		ariph[i] = ariph[i - 1] + i;
	}
	int lastRes = 0;

	for (int i = n-1; i>=0; --i)
	{
		if (s[i] == '1' && count == 0)
		{
			fIndx = i;
			++count;
		}

		if (s[i] == '1')
		{
			while (!maxInt.empty()
				&& std::abs(maxInt.begin()->second - maxInt.begin()->first) < std::abs(i - fIndx))
			{
				maxInt.erase(maxInt.begin());
			}
			auto found = maxInt.upper_bound(std::make_pair(i, fIndx));
			if (found == maxInt.end())
			{
				int c = (n - 1 - fIndx + 1);
				sum[i] = ariph[std::abs(fIndx - i)] + c * (std::abs(fIndx - i) + 1);
				res += sum[i];
			}
			else
			{
				int c = (found->first + std::abs(fIndx - i) - fIndx + 1);
				sum[i] = ariph[std::abs(fIndx - i)] + sum[found->first]
					- ariph[std::abs(fIndx - i) + 1] + c * (std::abs(fIndx - i) + 1);
				res += sum[i];
			}
			++count;
		}
		else
		{
			if (fIndx != n)
			{
				maxInt.emplace(i + 1, fIndx);
				fIndx = n;
				lastRes = sum[i+1];
			}
			sum[i] = i != n-1 ? sum[i + 1] : 0;
			res += lastRes;
			count = 0;
		}

	}
	std::cout << res<< std::endl;

	return 0;
}


#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <array>
#include <stdint.h>
#include <set>
#include <unordered_map>
#include <map>
#include <bitset>
#include <string>
#include <cmath>
#include <queue>
#include <iterator>
#include <xutility>
#include <iomanip>
#include <numeric>
//#include "dmSegmentTree.hpp"
#include <xstddef>
#include <random>
#include <functional>

using namespace std;

#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define forn(i, n) for(int i = 0; i < int(n); i++)

template <class T>
vector<T> ReadVec(const int count)
{
	vector<T> res(count);
	forn(i, count)
	{
		std::cin >> res[i];
	}
	return res;
}

template <class T>
void PrintVecOneLine(const vector<T>& src)
{
	forn(i, src.size())
	{
		std::cout << src[i];
		if (i + 1 != src.size())
			std::cout << " ";
	}
	std::cout << "\n";
}

template <class T>
void PrintVecManyLine(const vector<T>& src)
{
	forn(i, src.size())
	{
		std::cout << src[i] << "\n";
	}
}

std::vector<std::vector<int>> BuildGraph(int n,int m, bool oriented, int inc = 1)
{
	std::vector<std::vector<int>> res(n);
	forn(i, m)
	{
		int a, b;
		std::cin >> a >> b;
		res[a - inc].push_back(b - inc);
		if (oriented)
			continue;
		res[b - inc].push_back(a - inc);
	}
	return res;
}

std::vector<std::vector<int>> BuildGraph(
	int n,int m, bool oriented, std::vector<int64_t>& weight, int inc = 1)
{
	std::vector<std::vector<int>> res(n);
	weight.resize(m);
	forn(i, m)
	{
		int a, b;
		std::cin >> a >> b >> weight[i];
		res[a - inc].push_back(b - inc);
		if (oriented)
			continue;
		res[b - inc].push_back(a - inc);
	}
	return res;
}

//int64_t inf = std::numeric_limits<int64_t>::max();

//#define HOME
// BABB A
// BA BABB B
// (a^2 + b^2) - 2ab== (a + b)^2
// sum = a^2 + b^2 + c^2

struct comp
{
	bool operator()(const std::pair<int64_t, int64_t>& a, const std::pair<int64_t, int64_t>& b) const
	{
		return a.first < b.first;
	}
};
int main()
{
#ifdef HOME
	freopen("input.txt", "r", stdin);
#else
	std::ios_base::sync_with_stdio(0); std::cin.tie(0); std::cout.tie(0);
	std::cout.setf(std::ios::fixed); std::cout.precision(20);
#endif
	int64_t n;
	cin >> n;
	string s;
	cin >> s;
	int64_t count = 0;
	int64_t fIndx = n;
	std::vector<int64_t> sum(n, 0);
	//std::vector<int64_t> fakeSum(n, 0);
	std::vector<int64_t> ariph(n, 0);
	/*for (int i = 0; i < fakeSum.size(); ++i)
	{
		std::array<int, 2> longest = { 0,0 };
		int idx = 0;
		for (int j = i; j < fakeSum.size(); ++j)
		{
			if (s[j] == '1')
			{
				longest[idx]++;
				fakeSum[i] += std::max(longest[idx], longest[(idx + 1) % 2]);
			}
			else
			{
				fakeSum[i] += std::max(longest[idx], longest[(idx + 1) % 2]);
				if (j != i && s[j - 1] == '1')
				{
					longest[idx] = std::max(longest[idx], longest[(idx + 1) % 2]);
					idx = (idx + 1) % 2;
					longest[idx] = 0;
				}
			}

		}
	}
	cout << std::accumulate(ALL(fakeSum), 0) << endl;
*/
	std::set<std::pair<int64_t, int64_t>, comp> maxInt;
	int64_t res = 0;
	for (int64_t i = 1; i < n; ++i)
	{
		ariph[i] = ariph[i - 1] + i;
	}
	int64_t lastRes = 0;

	for (int64_t i = n-1; i>=0; --i)
	{
		if (s[i] == '1' && count == 0)
		{
			fIndx = i;
			++count;
		}

		if (s[i] == '1')
		{
			while (!maxInt.empty()
				&& std::abs(maxInt.begin()->second - maxInt.begin()->first) < std::abs(i - fIndx))
			{
				maxInt.erase(maxInt.begin());
			}
			auto found = maxInt.upper_bound(std::make_pair(i, fIndx));
			if (found == maxInt.end())
			{
				int64_t c = (n - 1 - fIndx + 1);
				sum[i] = ariph[std::abs(fIndx - i)] + c * (std::abs(fIndx - i) + 1);
				res += sum[i];
			}
			else
			{
				int64_t c = (found->first + std::abs(fIndx - i) - fIndx + 1);
				sum[i] = ariph[std::abs(fIndx - i)] + sum[found->first]
					- ariph[std::abs(fIndx - i) + 1] + c * (std::abs(fIndx - i) + 1);
				res += sum[i];
			}
			++count;
		}
		else
		{
			if (fIndx != n)
			{
				maxInt.emplace(i + 1, fIndx);
				fIndx = n;
				lastRes = sum[i+1];
			}
			sum[i] = i != n-1 ? sum[i + 1] : 0;
			res += lastRes;
			count = 0;
		}

	}
	std::cout << res<< std::endl;

	return 0;
}


#include <iomanip>
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
#include <map>
#include <queue>
#include <string>

#define ll long long
#define ull unsigned long long
#define mp make_pair
#define pb push_back
#define free variable1
#define y0 var1
#define rank var2

using namespace std;

const int N = 3000000;
const int MOD = 1e9+7;

int n;
string s;
int nxt[N];
int dp[N];
int one[N];

int main() {
    cin >> n;
    cin >> s;
    nxt[n] = n;
    ll sum = 0;
    ll ans = 0;
    one[n] = n;
    for (int i = n - 1; i >= 0; i--) {
        if (s[i] == '0') {
            ans += sum;
            dp[i] = 0;
            one[i] = one[i + 1];
            nxt[i] = one[i];
        }
        else {
            int pos;
            dp[i] = dp[i + 1] + 1;
            if (dp[nxt[i + 1]] > dp[i]) nxt[i] = nxt[i + 1];
            else nxt[i] = nxt[nxt[i + 1]];
            one[i] = i;
            if (nxt[i + 1] == n) sum += nxt[i + 1] - i;
            else sum += nxt[i + 1] + dp[i] - i - 1;
            ans += sum;
        }
    }
    cout << ans;
    return 0;
}


n = int(input())
s = input()

i = 0
ans = 0
curr = 0
prev = [-1] * 500005

while (i < n):
    if s[i] == '0':
        #print('0->', i, curr)
        ans += curr

    else:
        left = i
        right = i
        while (right+1 < n) and (s[right+1] == '1'):
            right += 1

        for j in range(right+1-left):
            curr += (left + j) - prev[j]
            #print(left, right, j, curr)
            ans += curr

            prev[j] = right - j

        i = right

    i += 1

print(ans)


n = int(input())
s = input()

i = 0
ans = 0
curr = 0
prev = [-1] * 100005

while (i < n):
    if s[i] == '0':
        #print('0->', i, curr)
        ans += curr

    else:
        left = i
        right = i
        while (right+1 < n) and (s[right+1] == '1'):
            right += 1

        for j in range(right+1-left):
            curr += (left + j) - prev[j]
            #print(left, right, j, curr)
            ans += curr

            prev[j] = right - j

        i = right

    i += 1

print(ans)


from sys import stdin
n= int(stdin.readline())
s = stdin.readline().strip()
total = 0
crnt = 0

hist = [0] * n
i = 0
while(i < n):
    if (s[i] == '0'):
        total += crnt
    else:
        #find longest segment of ones from here
        l = i
        r = i
        while(r+1 < n and s[r+1] == '1'):
            r += 1
        #Update with found segment
        #print(l,r, "l,r")
        for j in range(r-l+1):
            #print((l+j+1), hist[j])
            crnt += (l+j+1) - hist[j]
            total += crnt
            hist[j] = r-j+1
        #print()
        i = r
    i+= 1

print(total)


hist = [0]*1000005

def solve(n,s):
    cnt = 0
    tot = 0
    i = 0
    while i < n:
        if s[i] == '0':
            tot += cnt
        else:
            l = i
            r = i
            while r+1 < n and s[r+1] == '1':
                r+=1
            #print(r)
            for x in range(r-l+1):
                cnt += (l+x+1)-hist[x]
                tot += cnt
                hist[x] = r-x+1
            i = r
        i+=1
    return tot

n = int(input())
s = input()
print(solve(n,s))


hist = [0]*1000005
def solve(n,s):
    tot = 0
    cur = 0
    i = 0
    while i < n :
        if s[i] == '0':
            tot += cur
        else:
            l = i
            r = i
            while r+1 < n and s[r+1] == '1':
                r+=1
            for x in range(r-l+1):
                cur += (l+x+1)-hist[x]
                tot += cur
                hist[x] = r-x+1
            i = r
        i+=1
    return tot

n = int(input())
s = input()
print(solve(n,s))


n = int(input());a = map(int, input());acc = 0;back = 0;top = 0;cur = 0;s = []
for i,x in enumerate(a):
	if x == 0:cur = 0
	else:
		if cur > 0:s.pop()
		cur += 1
		if cur >= top:top = cur;back = (cur + 1) * (cur) // 2 + (i - cur + 1) * cur;s = [(cur, i)]
		else:
			back += i - (s[-1][1] - cur + 1)
			if cur >= s[-1][0]:s.pop()
			s += [(cur, i)]
	acc += back
print(acc)


from sys import stdin
def main():
    n = int(stdin.readline())
    s = stdin.readline().strip()
    r = [0] * n
    g = [[] for _ in xrange(n + 2)]
    a = [0] * n
    i = n - 1
    while i >= 0:
        if s[i] == '1':
            j = i
            while j >= 0 and s[j] == '1':
                r[j] = i + 1
                j -= 1
            while i > j:
                x = i - j
                if g[x+1]:
                    a[i] = x * (g[x+1][-1] - i) + a[g[x+1][-1]]
                else:
                    a[i] = x * (n - i)
                g[x].append(i)
                i -= 1
        else:
            i -= 1
    ans = c = 0
    for i, t in enumerate(r):
        c += 1
        if s[i] == '0':
            continue
        b = t - i
        if i == 0 or s[i-1] == '0':
            for j in xrange(1, b + 1):
                g[j].pop()
        u = b * (b + 1) / 2
        if g[b+1]:
            x = g[b+1][-1]
            u += (x - t) * b + a[x]
        else:
            u += (n - t) * b
        ans += c * u
        c = 0
    print ans
main()


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    int n;
    scanf("%d", &n);

    char* s = malloc((n + 1) * sizeof(*s));
    read(0, s, n + 1);

    long long* ar = malloc(n * sizeof(*ar));
    for (int i = 0; i < n; ar[i++] = 0) {}

    long long answer = 0, current = 0;
    for (int i = 0; i < n; i++)
    {
        if (s[i] == '0')
        {
            answer += current;
            continue;
        }

        int left = i, right = i;
        for ( ; (right < n) && (s[right + 1] == '1'); right++) {}
        for (int i = 1; i <= (right - left + 1); i++)
        {
            current += (left + i) - ar[i];
            answer += current;
            ar[i] = right - i + 2;
        }

        i = right;
    }

    printf("%lld\n", answer);
    fflush(stdout);
    _exit(0);
}


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    int n;
    scanf("%d", &n);

    char* s = malloc((n + 1) * sizeof(*s));
    scanf("%s", s);

    long long* ar = malloc(n * sizeof(*ar));
    for (int i = 0; i < n; ar[i++] = 0) {}

    long long answer = 0, current = 0;
    for (int i = 0; i < n; i++)
    {
        if (s[i] == '0')
        {
            answer += current;
            continue;
        }

        int left = i, right = i;
        for ( ; (right < n) && (s[right + 1] == '1'); right++) {}
        for (int i = 1; i <= (right - left + 1); i++)
        {
            current += (left + i) - ar[i];
            answer += current;
            ar[i] = right - i + 2;
        }

        i = right;
    }

    printf("%lld\n", answer);
    fflush(stdout);
    _exit(0);
}


# include <stdio.h>
# include <stdlib.h>
# include <string.h>

int main()
{
	long long number[2000005];
	long long a = 0;
	long long b = 0;
	int N;
	int S[2000005];

	scanf("%d",&N);
	int i;
	for (int i = 0; i < N; i=i+1)
	{
		char x;
		scanf("%c",&x);
		S[i] = (x - '0');
	}
	for (int i = 1; i <= N; ++i)
	{
		if (S[i] == 0)
		a = a + b;
		else
		{
			int l = i, r = i;
			while (r < N && S[r+1] == 1)
			r++;
			for (int x = 1; x <= (r-l+1); ++x)
			{
				b = b + (l-1+x) - number[x];
				a = a + b;
				number[x] = r-x+1;
			}
			i = r;
		}
	}

	printf("%l",a);

	return 0;
}


# include <stdio.h>
# include <stdlib.h>
# include <string.h>

typedef long long ll;

int main()
{
	long long number[2000005];
	long long a = 0;
	long long b = 0;
	int N;
	int S[2000005];

	scanf("%d",&N);
	int i;
	for (int i = 0; i < N; ++i)
	{
		char x;
		scanf("%c",&x);
		S[i] = (x - '0');
	}
	for (int i = 1; i <= N; ++i)
	{
		if (S[i] == 0)
		a = a + b;
		else
		{
			int l = i, r = i;
			while (r < N && S[r+1] == 1)
			r++;
			for (int x = 1; x <= (r-l+1); ++x)
			{
				b = b+ (l-1+x) - number[x];
				a = a+b;
				number[x] = r-x+1;
			}
			i = r;
		}
	}

	printf("%ll\n",a);

	return 0;
}


# include <stdio.h>
# include <stdlib.h>
# include <string.h>

int main()
{
	long long number[2000005];
	long long a = 0;
	long long b = 0;
	int N;
	int S[2000005];

	scanf("%d",&N);
	int i;
	for (int i = 0; i < N; ++i)
	{
		char x;
		scanf("%c",&x);
		S[i] = (x - '0');
	}
	for (int i = 1; i <= N; ++i)
	{
		if (S[i] == 0)
		a = a + b;
		else
		{
			int l = i, r = i;
			while (r < N && S[r+1] == 1)
			r++;
			for (int x = 1; x <= (r-l+1); ++x)
			{
				b = b+ (l-1+x) - number[x];
				a = a+b;
				number[x] = r-x+1;
			}
			i = r;
		}
	}

	printf("%l\n",a);

	return 0;
}


# include <stdio.h>
# include <stdlib.h>
# include <string.h>

typedef long long ll;

int main()
{
	long long number[2000005];
	long long a = 0;
	long long b = 0;
	int N;
	int S[2000005];

	scanf("%d",&N);
	int i;
	for (int i = 0; i <= N; ++i)
	{
		char x;
		scanf("%c",&x);
		S[i] = (x - '0');
	}
	for (int i = 1; i <= N; ++i)
	{
		if (S[i] == 0)
		a = a + b;
		else
		{
			int l = i, r = i;
			while (r < N && S[r+1] == 1)
			r++;
			for (int x = 1; x <= (r-l+1); ++x)
			{
				b = b+ (l-1+x) - number[x];
				a = a+b;
				number[x] = r-x+1;
			}
			i = r;
		}
	}

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

	return 0;
}


# include <stdio.h>
# include <stdlib.h>
# include <string.h>

typedef long long ll;

int main()
{
	long long number[2000005];
	long long a = 0;
	long long b = 0;
	int N;
	int S[2000005];

	scanf("%d",&N);
	int i;
	for (int i = 0; i < N; ++i)
	{
		char x;
		scanf("%c",&x);
		S[i] = (x - '0');
	}
	for (int i = 1; i <= N; ++i)
	{
		if (S[i] == 0)
		a = a + b;
		else
		{
			int l = i, r = i;
			while (r < N && S[r+1] == 1)
			r++;
			for (int x = 1; x <= (r-l+1); ++x)
			{
				b = b+ (l-1+x) - number[x];
				a = a+b;
				number[x] = r-x+1;
			}
			i = r;
		}
	}

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

	return 0;
}


function For(a, b, fn) {
  if (!fn) return For(0, a - 1, b);
  let res;
  for (let i = a; i <= b; i++) {
    if ((res = fn(i)) != null) return res;
  }
}
function ForR(a, b, fn) {
  if (!fn) return ForR(a - 1, 0, b);
  let res;
  for (let i = a; i >= b; i--) {
    if ((res = fn(i)) != null) return res;
  }
}

function Arr(a, b, fn) {
  if (typeof (b) == 'function') return Arr(0, a - 1, b);
  if (b < a) return [];
  let arr = Array(b - a + 1)
  for (let i = a; i <= b; i++) arr[i - a] = fn(i, arr);
  return arr;
}

Object.defineProperty(Object.prototype, '$k', {
  value: function () { return Object.keys(this) }
});
Object.defineProperty(Object.prototype, '$v', {
  value: function () { return Object.values(this) }
});
Object.defineProperty(Object.prototype, '$kv', {
  value: function () { return Object.entries(this) }
});
Array.prototype.sum = function (fn) { return this.reduce((p, v) => p + (fn ? fn(v) : v), 0) }
Array.prototype.uniq = function (fn) {
  var set = new Set();
  return this.filter(v => {
    var newValue = !set.has(fn ? fn(v) : v);
    set.add(fn ? fn(v) : v);
    return newValue;
  });
}
Array.prototype.toObj = function (fn) {
  return this.map(v => fn ? fn(v) : v).reduce((p, v) => {
    p[v[0]] = v[1];
    return p;
  }, {})
}
Array.prototype.min = function (fn) {
  let min = 1e20, index = -1, x;
  for (let i = 0; i < this.length; i++) {
    x = fn ? fn(this[i], i, this) : this[i];
    if (x < min) { min = x; index = i }
  }
  return [this[index], index, min];
}
Array.prototype.max = function (fn) {
  let max = -1e20, index = -1, x;
  for (let i = 0; i < this.length; i++) {
    x = fn ? fn(this[i], i, this) : this[i];
    if (x > max) { max = x; index = i }
  }
  return [this[index], index, max];
}
Array.prototype.rev = function (first, last) {
  for (let i = first; i < (first + last) / 2; i++) {
    [this[i], this[last - 1 - i + first]] = [this[last - 1 - i + first], this[i]]
  }
}
Array.prototype.set = function (pos, arr) {
  for (let i = pos; i < pos + arr.length; i++) {
    this[i] = arr[i - pos];
  }
}
Array.prototype.bin = function (comp, a, b) {
  let mid;
  while (a < b) {
    mid = (a + b) / 2 | 0;
    if (typeof comp == 'function' ? comp(this[mid]) : this[mid] < comp) a = mid + 1;
    else b = mid;
  }
  return a;
}
Array.prototype.cut = function (fn, a, b) {
  let arr = [];
  a = a || 0;
  b = b || (this.length - 1);
  let prev = a;
  for (let i = a; i <= b; i++) {
    if (i == b || fn(this[i], this[i + 1], i, this)) {
      arr.push(this.slice(prev, i + 1));
      prev = i + 1;
    }
  }
  return arr;
}

function gcd(a, b) {
  while (b) [a, b] = [b, a % b];
  return a;
}
function mul(a, b, m) {
  return ((a >> 16) * b % m * 65536 + (a & 65535) * b) % m
}
function pow(a, n, m) {
  let r = 1;
  while (n) n & 1 ? (r = mul(r, a, m), n--) : [a, n] = [mul(a, a, m), n >> 1]
  return r;
}
function inv(b, m) {
  for (var a = m, u = 0, v = 1, t; b; v = t)
    (t = a / b | 0, a -= t * b, u -= t * v, t = a, a = b, b = t, t = u, u = v);
  return (u + m) % m;
}

// let MOD = 1e9 + 7
// let gt = Arr(n, (i, a) => i == 0 ? 1 : mul(a[i - 1], i, MOD));
// let rgt = Arr(n, (i, a) => i <= 1 ? 1 : MOD - mul((MOD / i | 0), a[MOD % i], MOD));
// For(2, n - 1, i => { rgt[i] = mul(rgt[i], rgt[i - 1], MOD) });
// let nCk = (n, k) => mul(mul(gt[n], rgt[k], MOD), rgt[n - k], MOD);

// for (i = pos; i <= n; i += i & -i) fen[i]++; // start from index 1
// for (i = pos; i; i -= i & -i) ans += fen[i];

// let p = [2];
// for (let i = 3; i < 1e5; i += 2) {
//   let j, x = Math.sqrt(i);
//   for (j = 0; p[j] <= x; j++) if (i % p[j] == 0) break;
//   if (i % p[j] != 0) p.push(i);
// }

// let root = x => par[x] < 0 ? x : (par[x] = root(par[x]));
// let dsu = (x, y) => {
//   if ((x = root(x)) == (y = root(y))) return;
//   if (par[y] < par[x]) [x, y] = [y, x];
//   par[x] += par[y];
//   par[y] = x;
// }
// alpha = "abcdefghijklmnopqrstuvwxyz"

let input = '';
process.stdin.on('data', c => input += c);
process.stdin.on('end', main);
async function main() {
  let inp = input.split(/\s+/), _i = 0, $ = n => n != null ? inp.slice(_i, _i += n) : inp[_i++],
    out = [], log = console.log, asc = (a, b) => a - b, desc = (a, b) => b - a, { min, max, ceil, floor, sqrt, abs, log2 } = Math,
    bi = BigInt, rand = n => Math.random() * n | 0;

  let n = +$(), s = $()
  let res = 0n;
  let h = Arr(n + 1, i => -1), sh = 0, lh = 0;
  For(n, i => {
    if (s[i] == 0) {
      res += bi(sh);
      lh--;
      while (lh > 0) {
        h[lh] = h[lh + 1] + 1;
        lh--;
      }
      lh = 0;
      // log(0, res, h, sh, lh)
      return;
    }
    lh++;
    sh += i - h[lh];
    h[lh] = i - lh + 1;
    res += bi(sh);
    // log(1, res, h, sh, lh)
  })
  log(res + '');
}


using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;

// (づ°ω°)づﾐe★゜・。。・゜゜・。。・゜☆゜・。。・゜゜・。。・゜
public class Solver
{
    public void Solve()
    {
        for (int tt = 1; tt > 0; tt--)
        {
            int n = ReadInt();
            var a = ReadToken();

            var cnt = new long[n + 1];
            int c = 0, z = 0, pr = 0, pz = 0;
            for (int i = 0; i <= n; i++)
                if (i == n || a[i] == '0')
                {
                    if (c > 0)
                    {
                        for (int j = c; j > 0; j--)
                        {
                            int v = c - j;
                            int l = (v + 1) + pz + Math.Min(pr, j - 1);
                            int r = n - i + 1 + v;
                            cnt[j] += 1L * l * r - 1L * v * (v + 1) / 2;
                        }
                        pr = c;
                        c = 0;
                    }
                    z++;
                }
                else
                {
                    if (z > 0)
                        pz = z;
                    z = 0;
                    c++;
                }

            long sum = 0;
            long ans = 0;
            for (int i = n; i > 0; i--)
            {
                cnt[i] -= sum;
                ans += 1L * i * cnt[i];
                sum += cnt[i];
            }

            Write(ans);
        }
    }

    #region Main

    protected static TextReader reader;
    protected static TextWriter writer;
    static void Main()
    {
#if DEBUG
        reader = new StreamReader("..\\..\\input.txt");
        //reader = new StreamReader(Console.OpenStandardInput());
        writer = Console.Out;
        //writer = new StreamWriter("..\\..\\output.txt");
#else
        reader = new StreamReader(Console.OpenStandardInput());
        writer = new StreamWriter(Console.OpenStandardOutput());
        //reader = new StreamReader("input.txt");
        //writer = new StreamWriter("output.txt");
#endif
        try
        {
            new Solver().Solve();
            //var thread = new Thread(new Solver().Solve, 1024 * 1024 * 128);
            //thread.Start();
            //thread.Join();
        }
        catch (Exception ex)
        {
#if DEBUG
            Console.WriteLine(ex);
#else
            throw;
#endif
        }
        reader.Close();
        writer.Close();
    }

    #endregion

    #region Read / Write
    private static Queue<string> currentLineTokens = new Queue<string>();
    private static string[] ReadAndSplitLine() { return reader.ReadLine().Split(new[] { ' ', '\t', }, StringSplitOptions.RemoveEmptyEntries); }
    public static string ReadToken() { while (currentLineTokens.Count == 0) currentLineTokens = new Queue<string>(ReadAndSplitLine()); return currentLineTokens.Dequeue(); }
    public static int ReadInt() { return int.Parse(ReadToken()); }
    public static long ReadLong() { return long.Parse(ReadToken()); }
    public static double ReadDouble() { return double.Parse(ReadToken(), CultureInfo.InvariantCulture); }
    public static int[] ReadIntArray() { return ReadAndSplitLine().Select(int.Parse).ToArray(); }
    public static long[] ReadLongArray() { return ReadAndSplitLine().Select(long.Parse).ToArray(); }
    public static double[] ReadDoubleArray() { return ReadAndSplitLine().Select(s => double.Parse(s, CultureInfo.InvariantCulture)).ToArray(); }
    public static int[][] ReadIntMatrix(int numberOfRows) { int[][] matrix = new int[numberOfRows][]; for (int i = 0; i < numberOfRows; i++) matrix[i] = ReadIntArray(); return matrix; }
    public static int[][] ReadAndTransposeIntMatrix(int numberOfRows)
    {
        int[][] matrix = ReadIntMatrix(numberOfRows); int[][] ret = new int[matrix[0].Length][];
        for (int i = 0; i < ret.Length; i++) { ret[i] = new int[numberOfRows]; for (int j = 0; j < numberOfRows; j++) ret[i][j] = matrix[j][i]; }
        return ret;
    }
    public static string[] ReadLines(int quantity) { string[] lines = new string[quantity]; for (int i = 0; i < quantity; i++) lines[i] = reader.ReadLine().Trim(); return lines; }
    public static void WriteArray<T>(IEnumerable<T> array) { writer.WriteLine(string.Join(" ", array)); }
    public static void Write(params object[] array) { WriteArray(array); }
    public static void WriteLines<T>(IEnumerable<T> array) { foreach (var a in array) writer.WriteLine(a); }
    private class SDictionary<TKey, TValue> : Dictionary<TKey, TValue>
    {
        public new TValue this[TKey key]
        {
            get { return ContainsKey(key) ? base[key] : default(TValue); }
            set { base[key] = value; }
        }
    }
    private static T[] Init<T>(int size) where T : new() { var ret = new T[size]; for (int i = 0; i < size; i++) ret[i] = new T(); return ret; }
    #endregion
}


using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;

// (づ°ω°)づﾐe★゜・。。・゜゜・。。・゜☆゜・。。・゜゜・。。・゜
public class Solver
{
    long Fun(int n, string a)
    {
        var cnt = new long[n + 1];
        var last = new int[n + 1];
        int c = 0;
        for (int i = 0; i <= n; i++)
            if (i == n || a[i] == '0')
            {
                if (c > 0)
                {
                    for (int j = c; j > 0; j--)
                    {
                        int v = c - j;
                        int l = i - j - last[j] + 1;
                        int r = n - i + 1 + v;
                        cnt[j] += 1L * l * r - 1L * v * (v + 1) / 2;
                        last[j] = i - j + 1;
                    }
                    c = 0;
                }
            }
            else
            {
                c++;
            }

        long sum = 0;
        long ans = 0;
        for (int i = n; i > 0; i--)
        {
            cnt[i] -= sum;
            ans += 1L * i * cnt[i];
            sum += cnt[i];
        }

        return ans;
    }

    public void Solve()
    {
        for (int tt = 1; tt > 0; tt--)
        {
            int n = ReadInt();
            var a = ReadToken();

            Write(Fun(n, a));
        }
    }

    #region Main

    protected static TextReader reader;
    protected static TextWriter writer;
    static void Main()
    {
#if DEBUG
        reader = new StreamReader("..\\..\\input.txt");
        //reader = new StreamReader(Console.OpenStandardInput());
        writer = Console.Out;
        //writer = new StreamWriter("..\\..\\output.txt");
#else
        reader = new StreamReader(Console.OpenStandardInput());
        writer = new StreamWriter(Console.OpenStandardOutput());
        //reader = new StreamReader("input.txt");
        //writer = new StreamWriter("output.txt");
#endif
        try
        {
            new Solver().Solve();
            //var thread = new Thread(new Solver().Solve, 1024 * 1024 * 128);
            //thread.Start();
            //thread.Join();
        }
        catch (Exception ex)
        {
#if DEBUG
            Console.WriteLine(ex);
#else
            throw;
#endif
        }
        reader.Close();
        writer.Close();
    }

    #endregion

    #region Read / Write
    private static Queue<string> currentLineTokens = new Queue<string>();
    private static string[] ReadAndSplitLine() { return reader.ReadLine().Split(new[] { ' ', '\t', }, StringSplitOptions.RemoveEmptyEntries); }
    public static string ReadToken() { while (currentLineTokens.Count == 0) currentLineTokens = new Queue<string>(ReadAndSplitLine()); return currentLineTokens.Dequeue(); }
    public static int ReadInt() { return int.Parse(ReadToken()); }
    public static long ReadLong() { return long.Parse(ReadToken()); }
    public static double ReadDouble() { return double.Parse(ReadToken(), CultureInfo.InvariantCulture); }
    public static int[] ReadIntArray() { return ReadAndSplitLine().Select(int.Parse).ToArray(); }
    public static long[] ReadLongArray() { return ReadAndSplitLine().Select(long.Parse).ToArray(); }
    public static double[] ReadDoubleArray() { return ReadAndSplitLine().Select(s => double.Parse(s, CultureInfo.InvariantCulture)).ToArray(); }
    public static int[][] ReadIntMatrix(int numberOfRows) { int[][] matrix = new int[numberOfRows][]; for (int i = 0; i < numberOfRows; i++) matrix[i] = ReadIntArray(); return matrix; }
    public static int[][] ReadAndTransposeIntMatrix(int numberOfRows)
    {
        int[][] matrix = ReadIntMatrix(numberOfRows); int[][] ret = new int[matrix[0].Length][];
        for (int i = 0; i < ret.Length; i++) { ret[i] = new int[numberOfRows]; for (int j = 0; j < numberOfRows; j++) ret[i][j] = matrix[j][i]; }
        return ret;
    }
    public static string[] ReadLines(int quantity) { string[] lines = new string[quantity]; for (int i = 0; i < quantity; i++) lines[i] = reader.ReadLine().Trim(); return lines; }
    public static void WriteArray<T>(IEnumerable<T> array) { writer.WriteLine(string.Join(" ", array)); }
    public static void Write(params object[] array) { WriteArray(array); }
    public static void WriteLines<T>(IEnumerable<T> array) { foreach (var a in array) writer.WriteLine(a); }
    private class SDictionary<TKey, TValue> : Dictionary<TKey, TValue>
    {
        public new TValue this[TKey key]
        {
            get { return ContainsKey(key) ? base[key] : default(TValue); }
            set { base[key] = value; }
        }
    }
    private static T[] Init<T>(int size) where T : new() { var ret = new T[size]; for (int i = 0; i < size; i++) ret[i] = new T(); return ret; }
    #endregion
}


using System;
using System.Buffers;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using CodeforcesRaifRound1.Questions;

namespace CodeforcesRaifRound1.Questions
{
    public class QuestionF : AtCoderQuestionBase
    {
        [MethodImpl(MethodImplOptions.AggressiveOptimization)]
        public override void Solve(IOManager io)
        {
            _ = io.ReadInt();
            var s = io.ReadString();

            long result = 0;
            long current = 0;

            var last = new int[s.Length + 1];

            for (int r = 0; r < s.Length; r++)
            {
                if (s[r] == '0')
                {
                    result += current;
                }
                else
                {
                    var l = r;
                    while (r + 1 < s.Length && s[r + 1] == '1')
                    {
                        r++;
                    }

                    for (int length = 1; length <= r - l + 1; length++)
                    {
                        current += (l + length) - last[length];
                        result += current;
                        last[length] = r - length + 2;
                    }
                }
            }

            io.WriteLine(result);
        }
    }
}

namespace CodeforcesRaifRound1
{
    class Program
    {
        static void Main(string[] args)
        {
            IAtCoderQuestion question = new QuestionF();
            using var io = new IOManager(Console.OpenStandardInput(), Console.OpenStandardOutput());
            question.Solve(io);
        }
    }
}

#region Base Class

namespace CodeforcesRaifRound1.Questions
{
    public interface IAtCoderQuestion
    {
        string Solve(string input);
        void Solve(IOManager io);
    }

    public abstract class AtCoderQuestionBase : IAtCoderQuestion
    {
        public string Solve(string input)
        {
            var inputStream = new MemoryStream(Encoding.UTF8.GetBytes(input));
            var outputStream = new MemoryStream();
            using var manager = new IOManager(inputStream, outputStream);

            Solve(manager);
            manager.Flush();

            outputStream.Seek(0, SeekOrigin.Begin);
            var reader = new StreamReader(outputStream);
            return reader.ReadToEnd();
        }

        public abstract void Solve(IOManager io);
    }
}

#endregion

#region Utils

namespace CodeforcesRaifRound1
{
    public class IOManager : IDisposable
    {
        private readonly BinaryReader _reader;
        private readonly StreamWriter _writer;
        private bool _disposedValue;
        private byte[] _buffer = new byte[1024];
        private int _length;
        private int _cursor;
        private bool _eof;

        const char ValidFirstChar = '!';
        const char ValidLastChar = '~';

        public IOManager(Stream input, Stream output)
        {
            _reader = new BinaryReader(input);
            _writer = new StreamWriter(output) { AutoFlush = false };
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private char ReadAscii()
        {
            if (_cursor == _length)
            {
                _cursor = 0;
                _length = _reader.Read(_buffer);

                if (_length == 0)
                {
                    if (!_eof)
                    {
                        _eof = true;
                        return char.MinValue;
                    }
                    else
                    {
                        ThrowEndOfStreamException();
                    }
                }
            }

            return (char)_buffer[_cursor++];
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public char ReadChar()
        {
            char c;
            while (!IsValidChar(c = ReadAscii())) { }
            return c;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public string ReadString()
        {
            var builder = new StringBuilder();
            char c;
            while (!IsValidChar(c = ReadAscii())) { }

            do
            {
                builder.Append(c);
            } while (IsValidChar(c = ReadAscii()));

            return builder.ToString();
        }

        public int ReadInt() => (int)ReadLong();

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public long ReadLong()
        {
            long result = 0;
            bool isPositive = true;
            char c;

            while (!IsNumericChar(c = ReadAscii())) { }

            if (c == '-')
            {
                isPositive = false;
                c = ReadAscii();
            }

            do
            {
                result *= 10;
                result += c - '0';
            } while (IsNumericChar(c = ReadAscii()));

            return isPositive ? result : -result;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private Span<char> ReadChunk(Span<char> span)
        {
            var i = 0;
            char c;
            while (!IsValidChar(c = ReadAscii())) { }

            do
            {
                span[i++] = c;
            } while (IsValidChar(c = ReadAscii()));

            return span.Slice(0, i);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public double ReadDouble() => double.Parse(ReadChunk(stackalloc char[32]));

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public decimal ReadDecimal() => decimal.Parse(ReadChunk(stackalloc char[32]));

        public int[] ReadIntArray(int n)
        {
            var a = new int[n];
            for (int i = 0; i < a.Length; i++)
            {
                a[i] = ReadInt();
            }
            return a;
        }

        public long[] ReadLongArray(int n)
        {
            var a = new long[n];
            for (int i = 0; i < a.Length; i++)
            {
                a[i] = ReadLong();
            }
            return a;
        }

        public double[] ReadDoubleArray(int n)
        {
            var a = new double[n];
            for (int i = 0; i < a.Length; i++)
            {
                a[i] = ReadDouble();
            }
            return a;
        }

        public decimal[] ReadDecimalArray(int n)
        {
            var a = new decimal[n];
            for (int i = 0; i < a.Length; i++)
            {
                a[i] = ReadDecimal();
            }
            return a;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void WriteLine<T>(T value) => _writer.WriteLine(value.ToString());

        public void WriteLine<T>(IEnumerable<T> values, char separator)
        {
            var e = values.GetEnumerator();
            if (e.MoveNext())
            {
                _writer.Write(e.Current.ToString());

                while (e.MoveNext())
                {
                    _writer.Write(separator);
                    _writer.Write(e.Current.ToString());
                }
            }

            _writer.WriteLine();
        }

        public void WriteLine<T>(Span<T> values, char separator) => WriteLine((ReadOnlySpan<T>)values, separator);

        public void WriteLine<T>(ReadOnlySpan<T> values, char separator)
        {
            for (int i = 0; i < values.Length - 1; i++)
            {
                _writer.Write(values[i]);
                _writer.Write(separator);
            }

            if (values.Length > 0)
            {
                _writer.Write(values[^1]);
            }

            _writer.WriteLine();
        }

        public void Flush() => _writer.Flush();

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static bool IsValidChar(char c) => ValidFirstChar <= c && c <= ValidLastChar;

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static bool IsNumericChar(char c) => ('0' <= c && c <= '9') || c == '-';

        private void ThrowEndOfStreamException() => throw new EndOfStreamException();

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposedValue)
            {
                if (disposing)
                {
                    _reader.Dispose();
                    _writer.Flush();
                    _writer.Dispose();
                }

                _disposedValue = true;
            }
        }

        public void Dispose()
        {
            Dispose(disposing: true);
            GC.SuppressFinalize(this);
        }
    }

    public static class UtilExtensions
    {
        public static bool ChangeMax<T>(ref this T value, T other) where T : struct, IComparable<T>
        {
            if (value.CompareTo(other) < 0)
            {
                value = other;
                return true;
            }
            return false;
        }

        public static bool ChangeMin<T>(ref this T value, T other) where T : struct, IComparable<T>
        {
            if (value.CompareTo(other) > 0)
            {
                value = other;
                return true;
            }
            return false;
        }

        public static void SwapIfLargerThan<T>(ref this T a, ref T b) where T : struct, IComparable<T>
        {
            if (a.CompareTo(b) > 0)
            {
                (a, b) = (b, a);
            }
        }

        public static void SwapIfSmallerThan<T>(ref this T a, ref T b) where T : struct, IComparable<T>
        {
            if (a.CompareTo(b) < 0)
            {
                (a, b) = (b, a);
            }
        }

        public static void Sort<T>(this T[] array) where T : IComparable<T> => Array.Sort(array);
        public static void Sort<T>(this T[] array, Comparison<T> comparison) => Array.Sort(array, comparison);
    }

    public static class CollectionExtensions
    {
        private class ArrayWrapper<T>
        {
            public T[] Array;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Span<T> AsSpan<T>(this List<T> list)
        {
            return Unsafe.As<ArrayWrapper<T>>(list).Array.AsSpan(0, list.Count);
        }

        public static void Fill<T>(this T[] array, T value) => array.AsSpan().Fill(value);
        public static void Fill<T>(this T[,] array, T value) => MemoryMarshal.CreateSpan(ref array[0, 0], array.Length).Fill(value);
        public static void Fill<T>(this T[,,] array, T value) => MemoryMarshal.CreateSpan(ref array[0, 0, 0], array.Length).Fill(value);
        public static void Fill<T>(this T[,,,] array, T value) => MemoryMarshal.CreateSpan(ref array[0, 0, 0, 0], array.Length).Fill(value);
    }
}

#endregion


//spnauti-rusT {{{
use std::io::*; use std::str::{self,*}; use std::fmt::Debug;
#[allow(unused_imports)] use std::cmp::Ordering::{self,*};
#[allow(unused_imports)] use std::ops::{self,*};
#[allow(unused_imports)] use std::iter::{self,*};
#[allow(unused_imports)] use std::collections::*;
#[allow(unused_imports)] use std::cell::*;
#[allow(unused_macros)] macro_rules! min {
	($x:expr,$y:expr) => {{ let b=$y; let a=&mut$x; if b < *a {*a=b; true} else {false} }};
}
#[allow(unused_macros)] macro_rules! max {
	($x:expr,$y:expr) => {{ let b=$y; let a=&mut$x; if b > *a {*a=b; true} else {false} }};
}
#[allow(unused_macros)] macro_rules! l {
	($($v:ident),+ =$e:expr) => {$(let$v=$e;)+};
	($($v:ident),+:$t:ty=$e:expr) => {$(let$v:$t=$e;)+};
	(mut $($v:ident),+ =$e:expr) => {$(let mut$v=$e;)+};
	(mut $($v:ident),+:$t:ty=$e:expr) => {$(let mut$v:$t=$e;)+};
}
#[allow(unused_macros)] macro_rules! v {
	([$d:expr]$($s:tt)+) => {vec![v!($($s)+);$d]};
	([]) => {Vec::new()}; ([$e:expr]) => {Vec::with_capacity($e)}; (=$e:expr) => {$e};
}
#[allow(unused_macros)] macro_rules! rep { {[$c:expr]$($s:tt)+} => {for _ in 0..$c {$($s)+}} }
#[allow(dead_code)] fn reader() -> WordReaderC { WordReaderC::new() }
#[allow(dead_code)] fn writer() -> BufWriter<Stdout> { BufWriter::new(stdout()) }
struct WordReaderC {buf: Vec<u8>, pos: usize, q: std::io::StdinLock<'static>}//'
#[allow(dead_code)] impl WordReaderC {
	fn new() -> Self {
		let r = unsafe {&*Box::into_raw(Box::new(stdin()))};
		Self { q: r.lock(), buf: Vec::new(), pos: 0 }
	}
	fn next_line(&mut self) -> bool {
		self.buf.clear(); self.pos = 0;
		self.q.read_until(b'\n', &mut self.buf).unwrap_or(0) > 0
	}
	fn is_ws(c: u8) -> bool {
		c == b' ' || c == b'\r' || c == b'\n' || c == b'\t'
	}
	fn byte(&mut self) -> Option<u8> {
		if self.pos == self.buf.len() { if !self.next_line() { return None; } }
		self.pos += 1; Some(self.buf[self.pos - 1])
	}
	fn vb(&mut self) -> Vec<u8> {
		let mut s = Vec::with_capacity(8);
		let mut f = false;
		loop {
			if let Some(c) = self.byte() {
				if !Self::is_ws(c) {
					s.push(c);
					f = true;
				} else if f { break; }
			} else { break; }
		}
		s
	}
	fn s(&mut self) -> String { String::from_utf8(self.vb()).expect("invalid utf8") }
	fn i(&mut self) ->    i32 { self.p() }
	fn l(&mut self) ->    i64 { self.p() }
	fn u(&mut self) ->  usize { self.p() }
	fn f(&mut self) ->    f64 { self.p() }
	fn vi(&mut self, n: usize) -> Vec<i32> { self.vp(n) }
	fn vl(&mut self, n: usize) -> Vec<i64> { self.vp(n) }
	fn vu(&mut self, n: usize) -> Vec<usize> { self.vp(n) }
	fn ii(&mut self, n: usize) -> impl Iterator<Item=i32> { self.ip(n).into_iter() }
	fn iu(&mut self, n: usize) -> impl Iterator<Item=usize> { self.ip(n).into_iter() }
	fn p<T: FromStr>(&mut self) -> T where T::Err: Debug {
		let w = self.vb(); str::from_utf8(w.as_ref()).unwrap().parse::<T>().unwrap()
	}
	fn vp<T: FromStr>(&mut self, n: usize) -> Vec<T> where T::Err: Debug {
		(0..n).map(|_|self.p()).collect()
	}
	fn ip<T: FromStr>(&mut self, n: usize) -> impl Iterator<Item=T> where T::Err: Debug {
		self.vp(n).into_iter()
	}
}
//------------------- End rusT }}}

fn main() {
	let mut rin = reader();
	let mut rout = writer();

	let n = rin.u();
	let s = rin.vb();
	let mut a = v!([n+1] = 0);
	let mut sum = 0;
	let mut sol = 0_i64;
	let mut i = 0;
	while i < n {
		if s[i] == b'0' {
			i += 1;
			sol += sum;
		} else {
			let mut j = i;
			while j < n && s[j] == b'1' {
				j += 1;
			}
			let len = j - i;
			for k in 1..=len {
				sum -= a[k];
				a[k] = (i + len - k + 1) as i64;
				sum += (i + k) as i64;
				sol += sum;
			}
			i = j;
		}
		// writeln!(rout, "i {}  {} {} : {:?}", i, sum, sol, a).ok();
	}
	writeln!(rout, "{}", sol).ok();
}


#[allow(unused_imports)]
use ngtio::prelude::*;
// use ordtools::Ordtools;
use segbeats::Segbeats;

fn main() {
    let mut buf = ngtio::with_stdin();
    let n = buf.usize();
    let s = buf.string().chars().collect::<Vec<_>>();

    let mut ans = 0u64;
    let mut k = 0;
    let mut dp = Segbeats::new(&vec![0u64; n]);
    for (i, &c) in s.iter().enumerate() {
        match c {
            '0' => {
                for j in 1..=k {
                    dp.change_max(i - j..i - j + 1, j as u64);
                }
                k = 0;
            }
            '1' => {
                dp.change_max(..i - k, k as u64 + 1);
                k += 1;
            }
            _ => panic!(),
        }
        ans += dp.query_sum(..i + 1) + k as u64 * (k as u64 + 1) / 2;
    }
    println!("{}", ans);
}
//
// fn main() {
//     let mut buf = ngtio::with_stdin();
//     let n = buf.usize();
//     let s = buf.string().chars().collect::<Vec<_>>();
//
//     let mut ans = 0u64;
//     let mut k = 0;
//     let mut dp = vec![0u64; n];
//     for (i, &c) in s.iter().enumerate() {
//         match c {
//             '0' => {
//                 for j in 1..=k {
//                     dp[i - j] = j as u64;
//                 }
//                 k = 0;
//             }
//             '1' => {
//                 dp[0..i - k]
//                     .iter_mut()
//                     .for_each(|x| x.change_max(k as u64 + 1));
//                 k += 1;
//             }
//             _ => panic!(),
//         }
//         lg!((k, &dp));
//         ans += dp[0..i + 1].iter().sum::<u64>() + k as u64 * (k as u64 + 1) / 2;
//     }
//     println!("{}", ans);
// }
//
// open {{{
#[allow(dead_code)]
mod open {
    use std::ops::{Bound, Range, RangeBounds};

    pub fn open(len: usize, range: impl RangeBounds<usize>) -> Range<usize> {
        use Bound::*;
        (match range.start_bound() {
            Unbounded => 0,
            Included(&x) => x,
            Excluded(&x) => x + 1,
        })..(match range.end_bound() {
            Excluded(&x) => x,
            Included(&x) => x + 1,
            Unbounded => len,
        })
    }
}
// }}}
// segbeats {{{
#[allow(dead_code)]
mod segbeats {
    use crate::open::open;
    use std::{
        cell::RefCell,
        fmt::Debug,
        ops::{Add, AddAssign, Range, RangeBounds, Sub, SubAssign},
    };

    #[derive(Debug, Clone, PartialEq)]
    pub struct Segbeats<T> {
        len: usize,
        lg: u32,
        table: RefCell<Vec<Node<T>>>,
    }

    impl<T: Elm> Segbeats<T> {
        pub fn new(src: &[T]) -> Self {
            let len = src.len().next_power_of_two();
            let lg = len.trailing_zeros();
            let mut table = vec![Node::new(); 2 * len];
            for (i, &x) in src.iter().enumerate() {
                table[len + i] = Node::single(x);
            }
            (1..len)
                .rev()
                .for_each(|i| table[i] = Node::merge(table[2 * i], table[2 * i + 1]));
            Self {
                len,
                lg,
                table: RefCell::new(table),
            }
        }
        pub fn change_min(&mut self, range: impl Clone + RangeBounds<usize>, x: T) {
            let range = open(self.len, range);
            self.dfs::<ChangeMin<T>>(range, x)
        }
        pub fn change_max(&mut self, range: impl Clone + RangeBounds<usize>, x: T) {
            let range = open(self.len, range);
            self.dfs::<ChangeMax<T>>(range, x)
        }
        pub fn query_min(&self, range: impl RangeBounds<usize>) -> T {
            let range = open(self.len, range);
            self.dfs::<QueryMin<T>>(range, ())
        }
        pub fn query_max(&self, range: impl RangeBounds<usize>) -> T {
            let range = open(self.len, range);
            self.dfs::<QueryMax<T>>(range, ())
        }
        pub fn query_sum(&self, range: impl RangeBounds<usize>) -> T {
            let range = open(self.len, range);
            self.dfs::<QuerySum<T>>(range, ())
        }
        fn push(&self, i: usize) {
            let x = self.table.borrow()[i].max[0];
            for j in 2 * i..2 * i + 2 {
                let node = self.table.borrow()[j];
                if node.max[1] < x && x < node.max[0] {
                    self.table.borrow_mut()[j].change_min(x);
                }
            }
            let x = self.table.borrow()[i].min[0];
            for j in 2 * i..2 * i + 2 {
                let node = self.table.borrow()[j];
                if node.min[0] < x && x < node.min[1] {
                    self.table.borrow_mut()[j].change_max(x);
                }
            }
        }
        fn dfs<D: Dfs<Value = T>>(&self, range: Range<usize>, x: D::Param) -> D::Output {
            self.dfs_impl::<D>(1, 0..self.len, range, x)
        }
        fn dfs_impl<D: Dfs<Value = T>>(
            &self,
            root: usize,
            subtree: Range<usize>,
            range: Range<usize>,
            x: D::Param,
        ) -> D::Output {
            if disjoint(&range, &subtree) || D::break_condition(self.table.borrow()[root], x) {
                D::identity()
            } else if contains(&range, &subtree) && D::tag_condition(self.table.borrow()[root], x) {
                D::tag(&mut self.table.borrow_mut()[root], x);
                D::extract(self.table.borrow()[root])
            } else {
                let Range { start, end } = subtree;
                let mid = (start + end) / 2;
                self.push(root);
                let l = self.dfs_impl::<D>(root * 2, start..mid, range.clone(), x);
                let r = self.dfs_impl::<D>(root * 2 + 1, mid..end, range, x);
                self.update(root);
                D::merge(l, r)
            }
        }
        fn update(&self, i: usize) {
            let x = Node::merge(self.table.borrow()[2 * i], self.table.borrow()[2 * i + 1]);
            self.table.borrow_mut()[i] = x;
        }
    }

    trait Dfs {
        type Value: Elm;
        type Param: Copy + Debug;
        type Output: Debug;
        fn identity() -> Self::Output;
        fn break_condition(_node: Node<Self::Value>, _x: Self::Param) -> bool {
            false
        }
        fn tag_condition(_node: Node<Self::Value>, _x: Self::Param) -> bool {
            true
        }
        fn tag(_node: &mut Node<Self::Value>, _x: Self::Param) {}
        fn merge(left: Self::Output, right: Self::Output) -> Self::Output;
        fn extract(node: Node<Self::Value>) -> Self::Output;
    }
    struct ChangeMin<T>(std::marker::PhantomData<T>);
    impl<T: Elm> Dfs for ChangeMin<T> {
        type Value = T;
        type Param = T;
        type Output = ();
        fn identity() -> Self::Output {}
        fn break_condition(node: Node<T>, x: Self::Param) -> bool {
            node.max[0] <= x
        }
        fn tag_condition(node: Node<T>, x: Self::Param) -> bool {
            node.max[1] < x
        }
        fn tag(node: &mut Node<Self::Value>, x: Self::Param) {
            node.change_min(x);
        }
        fn merge(_: (), _: ()) {}
        fn extract(_node: Node<T>) {}
    }
    struct ChangeMax<T>(std::marker::PhantomData<T>);
    impl<T: Elm> Dfs for ChangeMax<T> {
        type Value = T;
        type Param = T;
        type Output = ();
        fn identity() -> Self::Output {}
        fn break_condition(node: Node<T>, x: Self::Param) -> bool {
            x <= node.min[0]
        }
        fn tag_condition(node: Node<T>, x: Self::Param) -> bool {
            x < node.min[1]
        }
        fn tag(node: &mut Node<Self::Value>, x: Self::Param) {
            node.change_max(x);
        }
        fn merge(_: (), _: ()) {}
        fn extract(_node: Node<T>) {}
    }
    struct QueryMin<T>(std::marker::PhantomData<T>);
    impl<T: Elm> Dfs for QueryMin<T> {
        type Value = T;
        type Param = ();
        type Output = T;
        fn identity() -> Self::Output {
            T::max_value()
        }
        fn merge(left: T, right: T) -> T {
            left.min(right)
        }
        fn extract(node: Node<T>) -> T {
            node.min[0]
        }
    }
    struct QueryMax<T>(std::marker::PhantomData<T>);
    impl<T: Elm> Dfs for QueryMax<T> {
        type Value = T;
        type Param = ();
        type Output = T;
        fn identity() -> Self::Output {
            T::min_value()
        }
        fn merge(left: T, right: T) -> T {
            left.max(right)
        }
        fn extract(node: Node<T>) -> T {
            node.max[0]
        }
    }
    struct QuerySum<T>(std::marker::PhantomData<T>);
    impl<T: Elm> Dfs for QuerySum<T> {
        type Value = T;
        type Param = ();
        type Output = T;
        fn identity() -> Self::Output {
            T::zero()
        }
        fn merge(left: T, right: T) -> T {
            left + right
        }
        fn extract(node: Node<T>) -> T {
            node.sum
        }
    }

    #[derive(Debug, Clone, PartialEq, Copy, Eq)]
    struct Node<T> {
        max: [T; 2],
        c_max: u32,
        min: [T; 2],
        c_min: u32,
        sum: T,
    }
    impl<T: Elm> Node<T> {
        fn new() -> Self {
            Node {
                max: [T::min_value(), T::min_value()],
                c_max: 0,
                min: [T::max_value(), T::max_value()],
                c_min: 0,
                sum: T::zero(),
            }
        }
        fn single(x: T) -> Self {
            Node {
                max: [x, T::min_value()],
                c_max: 1,
                min: [x, T::max_value()],
                c_min: 1,
                sum: x,
            }
        }
        fn change_min(&mut self, x: T) {
            assert!(self.max[1] < x && x < self.max[0]);
            self.sum += (x - self.max[0]).mul_u32(self.c_max);
            for i in 0..2 {
                if self.min[i] == self.max[0] {
                    self.min[i] = x;
                }
            }
            self.max[0] = x;
        }
        fn change_max(&mut self, x: T) {
            assert!(self.min[0] < x && x < self.min[1]);
            self.sum += (x - self.min[0]).mul_u32(self.c_min);
            for i in 0..2 {
                if self.max[i] == self.min[0] {
                    self.max[i] = x;
                }
            }
            self.min[0] = x;
        }
        fn merge(left: Node<T>, right: Node<T>) -> Self {
            use std::cmp::Ordering;
            let (max, c_max) = {
                let [a, b] = left.max;
                let [c, d] = right.max;
                match a.cmp(&c) {
                    Ordering::Equal => ([a, b.max(d)], left.c_max + right.c_max),
                    Ordering::Greater => ([a, b.max(c)], left.c_max),
                    Ordering::Less => ([c, a.max(d)], right.c_max),
                }
            };
            let (min, c_min) = {
                let [a, b] = left.min;
                let [c, d] = right.min;
                match a.cmp(&c) {
                    Ordering::Equal => ([a, b.min(d)], left.c_min + right.c_min),
                    Ordering::Less => ([a, b.min(c)], left.c_min),
                    Ordering::Greater => ([c, a.min(d)], right.c_min),
                }
            };
            Self {
                max,
                c_max,
                min,
                c_min,
                sum: left.sum + right.sum,
            }
        }
    }

    fn contains(i: &Range<usize>, j: &Range<usize>) -> bool {
        i.start <= j.start && j.end <= i.end
    }
    fn disjoint(i: &Range<usize>, j: &Range<usize>) -> bool {
        i.end <= j.start || j.end <= i.start
    }

    pub trait Elm:
        Sized
        + std::fmt::Debug
        + Copy
        + Ord
        + Add<Output = Self>
        + AddAssign
        + Sub<Output = Self>
        + SubAssign
    {
        fn max_value() -> Self;
        fn min_value() -> Self;
        fn zero() -> Self;
        fn mul_u32(&self, x: u32) -> Self;
    }
    macro_rules! impl_elm {
        {$($ty:ident;)*} => {
            $(
                impl Elm for $ty {
                    fn min_value() -> Self {
                        std::$ty::MIN
                    }
                    fn max_value() -> Self {
                        std::$ty::MAX
                    }
                    fn zero() -> Self {
                        0
                    }
                    fn mul_u32(&self, x: u32) -> Self {
                        self * (x as $ty)
                    }
                }
            )*
        }
    }
    impl_elm! {
        u8; u16; u32; u64; u128; usize;
        i8; i16; i32; i64; i128; isize;
    }
}
// }}}
// dbg {{{
#[allow(dead_code)]
mod dbg {
    #[macro_export]
    macro_rules! lg {
        () => {
            $crate::eprintln!("[{}:{}]", $crate::file!(), $crate::line!());
        };
        ($val:expr) => {
            match $val {
                tmp => {
                    eprintln!("[{}:{}] {} = {:?}",
                        file!(), line!(), stringify!($val), &tmp);
                    tmp
                }
            }
        };
        ($val:expr,) => { $crate::lg!($val) };
        ($($val:expr),+ $(,)?) => {
            ($($crate::lg!($val)),+,)
        };
    }

    #[macro_export]
    macro_rules! lg_nl {
        () => {
            eprintln!("[{}:{}]", $crate::file!(), $crate::line!());
        };
        ($val:expr) => {
            match $val {
                tmp => {
                    eprintln!("[{}:{}] {}:\n{:?}", file!(), line!(), stringify!($val), tmp);
                    tmp
                }
            };
        };
    }

    #[macro_export]
    macro_rules! msg {
        () => {
            compile_error!();
        };
        ($msg:expr) => {
            $crate::eprintln!("[{}:{}][{}]", $crate::file!(), $crate::line!(), $msg);
        };
        ($msg:expr, $val:expr) => {
            match $val {
                tmp => {
                    eprintln!("[{}:{}][{}] {} = {:?}",
                        file!(), line!(), $msg, stringify!($val), &tmp);
                    tmp
                }
            }
        };
        ($msg:expr, $val:expr,) => { msg!($msg, $val) };
        ($msg:expr, $($val:expr),+ $(,)?) => {
            ($(msg!($msg, $val)),+,)
        };
    }

    #[macro_export]
    macro_rules! tabular {
        ($val:expr) => {
            $crate::lg_nl!(crate::dbg::Tabular($val))
        };
    }

    #[macro_export]
    macro_rules! boolean_table {
        ($val:expr) => {
            $crate::lg_nl!(crate::dbg::BooleanTable($val));
        };
    }

    #[macro_export]
    macro_rules! boolean_slice {
        ($val:expr) => {
            $crate::lg!(crate::dbg::BooleanSlice($val));
        };
    }

    use std::fmt::{Debug, Formatter};

    #[derive(Clone)]
    pub struct Tabular<'a, T: Debug>(pub &'a [T]);
    impl<'a, T: Debug> Debug for Tabular<'a, T> {
        fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
            for i in 0..self.0.len() {
                writeln!(f, "{:2} | {:?}", i, &self.0[i])?;
            }
            Ok(())
        }
    }

    #[derive(Clone)]
    pub struct BooleanTable<'a>(pub &'a [Vec<bool>]);
    impl<'a> Debug for BooleanTable<'a> {
        fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
            for i in 0..self.0.len() {
                writeln!(f, "{:2} | {:?}", i, BooleanSlice(&self.0[i]))?;
            }
            Ok(())
        }
    }

    #[derive(Clone)]
    pub struct BooleanSlice<'a>(pub &'a [bool]);
    impl<'a> Debug for BooleanSlice<'a> {
        fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
            write!(
                f,
                "{}",
                self.0
                    .iter()
                    .map(|&b| if b { "1 " } else { "0 " })
                    .collect::<String>()
            )?;
            Ok(())
        }
    }
}
// }}}
// ordtools {{{
#[allow(dead_code)]
mod ordtools {
    #![warn(missing_docs)]
    #![warn(missing_doc_code_examples)]

    pub trait Ordtools: PartialOrd + Sized {
        fn change_min(&mut self, mut rhs: Self) {
            if self > &mut rhs {
                *self = rhs;
            }
        }

        fn change_max(&mut self, mut rhs: Self) {
            if self < &mut rhs {
                *self = rhs;
            }
        }
    }

    impl<T: PartialOrd + Sized> Ordtools for T {}
}
// }}}
// ngtio {{{
#[allow(dead_code)]
mod ngtio {
    #![warn(missing_docs)]

    mod i {
        use std::{
            io::{self, BufRead},
            iter,
        };

        pub use multi_token::{Leaf, Parser, ParserTuple, RawTuple, Tuple, VecLen};
        pub use token::{Token, Usize1};

        pub fn with_stdin() -> Tokenizer<io::BufReader<io::Stdin>> {
            io::BufReader::new(io::stdin()).tokenizer()
        }

        pub fn with_str(src: &str) -> Tokenizer<&[u8]> {
            src.as_bytes().tokenizer()
        }

        pub struct Tokenizer<S: BufRead> {
            queue: Vec<String>, // FIXME: String のみにすると速そうです。
            scanner: S,
        }
        macro_rules! prim_method {
            ($name:ident: $T:ty) => {
#[allow(missing_docs)]
                pub fn $name(&mut self) -> $T {
                    <$T>::leaf().parse(self)
                }
            };
            ($name:ident) => {
                prim_method!($name: $name);
            };
        }
        macro_rules! prim_methods {
            ($name:ident: $T:ty; $($rest:tt)*) => {
                prim_method!($name:$T);
                prim_methods!($($rest)*);
            };
            ($name:ident; $($rest:tt)*) => {
                prim_method!($name);
                prim_methods!($($rest)*);
            };
            () => ()
        }
        impl<S: BufRead> Tokenizer<S> {
            pub fn token(&mut self) -> String {
                self.load();
                self.queue.pop().expect("入力が終了したのですが。")
            }
            pub fn new(scanner: S) -> Self {
                Self {
                    queue: Vec::new(),
                    scanner,
                }
            }
            fn load(&mut self) {
                while self.queue.is_empty() {
                    let mut s = String::new();
                    let length = self.scanner.read_line(&mut s).unwrap(); // 入力が UTF-8 でないときにエラーだそうです。
                    if length == 0 {
                        break;
                    }
                    self.queue = s.split_whitespace().rev().map(str::to_owned).collect();
                }
            }

            pub fn skip_line(&mut self) {
                assert!(
                    self.queue.is_empty(),
                    "行の途中で呼ばないでいただきたいです。現在のトークンキュー: {:?}",
                    &self.queue
                );
                self.load();
            }

            pub fn end(&mut self) {
                self.load();
                assert!(self.queue.is_empty(), "入力はまだあります！");
            }

            pub fn parse<T: Token>(&mut self) -> T::Output {
                T::parse(&self.token())
            }

            pub fn parse_collect<T: Token, B>(&mut self, n: usize) -> B
            where
                B: iter::FromIterator<T::Output>,
            {
                iter::repeat_with(|| self.parse::<T>()).take(n).collect()
            }

            pub fn tuple<T: RawTuple>(&mut self) -> <T::LeafTuple as Parser>::Output {
                T::leaf_tuple().parse(self)
            }

            pub fn vec<T: Token>(&mut self, len: usize) -> Vec<T::Output> {
                T::leaf().vec(len).parse(self)
            }

            pub fn vec_tuple<T: RawTuple>(
                &mut self,
                len: usize,
            ) -> Vec<<T::LeafTuple as Parser>::Output> {
                T::leaf_tuple().vec(len).parse(self)
            }

            pub fn vec2<T: Token>(&mut self, height: usize, width: usize) -> Vec<Vec<T::Output>> {
                T::leaf().vec(width).vec(height).parse(self)
            }

            pub fn vec2_tuple<T>(
                &mut self,
                height: usize,
                width: usize,
            ) -> Vec<Vec<<T::LeafTuple as Parser>::Output>>
            where
                T: RawTuple,
            {
                T::leaf_tuple().vec(width).vec(height).parse(self)
            }
            prim_methods! {
                u8; u16; u32; u64; u128; usize;
                i8; i16; i32; i64; i128; isize;
                char; string: String;
            }
        }

        mod token {
            use super::multi_token::Leaf;
            use std::{any, fmt, marker, str};

            pub trait Token: Sized {
                type Output;
                fn parse(s: &str) -> Self::Output;
                fn leaf() -> Leaf<Self> {
                    Leaf(marker::PhantomData)
                }
            }

            impl<T> Token for T
            where
                T: str::FromStr,
                <T as str::FromStr>::Err: fmt::Debug,
            {
                type Output = T;
                fn parse(s: &str) -> Self::Output {
                    s.parse().unwrap_or_else(|_| {
                        panic!("Parse error!: ({}: {})", s, any::type_name::<T>(),)
                    })
                }
            }

            pub struct Usize1 {}
            impl Token for Usize1 {
                type Output = usize;
                fn parse(s: &str) -> Self::Output {
                    usize::parse(s)
                        .checked_sub(1)
                        .expect("Parse error! (Zero substruction error of Usize1)")
                }
            }
        }

        mod multi_token {
            use super::{Token, Tokenizer};
            use std::{io::BufRead, iter, marker};

            pub trait Parser: Sized {
                type Output;
                fn parse<S: BufRead>(&self, server: &mut Tokenizer<S>) -> Self::Output;
                fn vec(self, len: usize) -> VecLen<Self> {
                    VecLen { len, elem: self }
                }
            }
            pub struct Leaf<T>(pub(super) marker::PhantomData<T>);
            impl<T: Token> Parser for Leaf<T> {
                type Output = T::Output;
                fn parse<S: BufRead>(&self, server: &mut Tokenizer<S>) -> T::Output {
                    server.parse::<T>()
                }
            }

            pub struct VecLen<T> {
                pub len: usize,
                pub elem: T,
            }
            impl<T: Parser> Parser for VecLen<T> {
                type Output = Vec<T::Output>;
                fn parse<S: BufRead>(&self, server: &mut Tokenizer<S>) -> Self::Output {
                    iter::repeat_with(|| self.elem.parse(server))
                        .take(self.len)
                        .collect()
                }
            }

            pub trait RawTuple {
                type LeafTuple: Parser;
                fn leaf_tuple() -> Self::LeafTuple;
            }
            pub trait ParserTuple {
                type Tuple: Parser;
                fn tuple(self) -> Self::Tuple;
            }
            pub struct Tuple<T>(pub T);
            macro_rules! impl_tuple {
                ($($t:ident: $T:ident),*) => {
                    impl<$($T),*> Parser for Tuple<($($T,)*)>
                        where
                            $($T: Parser,)*
                            {
                                type Output = ($($T::Output,)*);
#[allow(unused_variables)]
                                fn parse<S: BufRead >(&self, server: &mut Tokenizer<S>) -> Self::Output {
                                    match self {
                                        Tuple(($($t,)*)) => {
                                            ($($t.parse(server),)*)
                                        }
                                    }
                                }
                            }
                    impl<$($T: Token),*> RawTuple for ($($T,)*) {
                        type LeafTuple = Tuple<($(Leaf<$T>,)*)>;
                        fn leaf_tuple() -> Self::LeafTuple {
                            Tuple(($($T::leaf(),)*))
                        }
                    }
                    impl<$($T: Parser),*> ParserTuple for ($($T,)*) {
                        type Tuple = Tuple<($($T,)*)>;
                        fn tuple(self) -> Self::Tuple {
                            Tuple(self)
                        }
                    }
                };
            }
            impl_tuple!();
            impl_tuple!(t1: T1);
            impl_tuple!(t1: T1, t2: T2);
            impl_tuple!(t1: T1, t2: T2, t3: T3);
            impl_tuple!(t1: T1, t2: T2, t3: T3, t4: T4);
            impl_tuple!(t1: T1, t2: T2, t3: T3, t4: T4, t5: T5);
            impl_tuple!(t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6);
            impl_tuple!(t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6, t7: T7);
            impl_tuple!(
                t1: T1,
                t2: T2,
                t3: T3,
                t4: T4,
                t5: T5,
                t6: T6,
                t7: T7,
                t8: T8
            );
        }

        trait Scanner: BufRead + Sized {
            fn tokenizer(self) -> Tokenizer<Self> {
                Tokenizer::new(self)
            }
        }
        impl<R: BufRead> Scanner for R {}
    }

    pub use i::{with_stdin, with_str};

    pub mod prelude {
        pub use super::i::{Parser, ParserTuple, RawTuple, Token, Usize1};
    }
}
// }}}


// ---------- begin input macro ----------
// reference: https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8
macro_rules! input {
    (source = $s:expr, $($r:tt)*) => {
        let mut iter = $s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
    ($($r:tt)*) => {
        let s = {
            use std::io::Read;
            let mut s = String::new();
            std::io::stdin().read_to_string(&mut s).unwrap();
            s
        };
        let mut iter = s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
}

macro_rules! input_inner {
    ($iter:expr) => {};
    ($iter:expr, ) => {};
    ($iter:expr, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($iter, $t);
        input_inner!{$iter $($r)*}
    };
}

macro_rules! read_value {
    ($iter:expr, ( $($t:tt),* )) => {
        ( $(read_value!($iter, $t)),* )
    };
    ($iter:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($iter, $t)).collect::<Vec<_>>()
    };
    ($iter:expr, chars) => {
        read_value!($iter, String).chars().collect::<Vec<char>>()
    };
    ($iter:expr, bytes) => {
        read_value!($iter, String).bytes().collect::<Vec<u8>>()
    };
    ($iter:expr, usize1) => {
        read_value!($iter, usize) - 1
    };
    ($iter:expr, $t:ty) => {
        $iter.next().unwrap().parse::<$t>().expect("Parse error")
    };
}
// ---------- end input macro ----------

// どう計算するんだろ
// 分割統治
// セグ木再帰
// スタック

use std::cmp::*;

fn run() {
    input! {
        _n: usize,
        s: bytes,
    }
    let mut s = s.into_iter().map(|c| c == b'1').collect::<Vec<_>>();
    let mut ans = 0u64;
    let mut call = vec![s.as_mut_slice()];
    while let Some(s) = call.pop() {
        if s.len() == 1 {
            if s[0] {
                ans += 1;
            }
//        println!("{}", ans);
            continue;
        }
        let m = s.len() / 2;
        let (l, r) = s.split_at_mut(m);
        l.reverse();
        let mut x = 0;
        while x < l.len() && l[x] {
            x += 1;
        }
        let mut y = 0;
        while y < r.len() && r[y] {
            y += 1;
        }
        let (x, y) = (x, y);
        let mut memo = vec![];
        for a in [&l[x..], &r[y..]].iter() {
            let mut now = 0;
            let mut dp = vec![];
            for p in a.iter() {
                if *p {
                    now += 1;
                } else {
                    now = 0;
                }
                let v = max(now, *dp.last().unwrap_or(&0));
                dp.push(v);
            }
            memo.push(dp);
        }
        /*
        println!("{:?}", l);
        println!("{:?}", r);
        println!("{} {} {:?}", x, y, memo);
        */
        while memo[0].len() > 0 && memo[1].len() > 0 {
            let a = *memo[0].last().unwrap();
            let b = *memo[1].last().unwrap();
            if (max(a, b) as usize) < x + y {
                break;
            }
            if a < b {
                ans += (memo[0].len() + x) as u64 * b;
                memo[1].pop();
            } else {
                ans += (memo[1].len() + y) as u64 * a;
                memo[0].pop();
            }
        }
        while memo[1].last().map_or(false, |p| (*p as usize) >= x + y) {
            let p = memo[1].pop().unwrap();
            ans += (memo[0].len() + x) as u64 * p as u64;
        }
        while memo[0].last().map_or(false, |p| (*p as usize) >= x + y) {
            let p = memo[0].pop().unwrap();
            ans += (memo[1].len() + x) as u64 * p as u64;
        }
//        println!("{} {:?}", ans, memo);
        // 0 + 1 + 2 + .. + n
        let f = |n: usize| -> u64 {
            n as u64 * (n + 1) as u64 / 2
        };
        for _ in 0..memo[0].len() {
            ans += memo[1].len() as u64 * (x + y) as u64 + f(x + y) - f(x);
        }
        for x in 1..=x {
            ans += memo[1].len() as u64 * (x + y) as u64 + f(x + y) - f(x);
        }
//        println!("{}", ans);
        call.push(l);
        call.push(r);
    }
    println!("{}", ans);
}

fn main() {
    run();
}


// ---------- begin input macro ----------
// reference: https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8
macro_rules! input {
    (source = $s:expr, $($r:tt)*) => {
        let mut iter = $s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
    ($($r:tt)*) => {
        let s = {
            use std::io::Read;
            let mut s = String::new();
            std::io::stdin().read_to_string(&mut s).unwrap();
            s
        };
        let mut iter = s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
}

macro_rules! input_inner {
    ($iter:expr) => {};
    ($iter:expr, ) => {};
    ($iter:expr, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($iter, $t);
        input_inner!{$iter $($r)*}
    };
}

macro_rules! read_value {
    ($iter:expr, ( $($t:tt),* )) => {
        ( $(read_value!($iter, $t)),* )
    };
    ($iter:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($iter, $t)).collect::<Vec<_>>()
    };
    ($iter:expr, chars) => {
        read_value!($iter, String).chars().collect::<Vec<char>>()
    };
    ($iter:expr, bytes) => {
        read_value!($iter, String).bytes().collect::<Vec<u8>>()
    };
    ($iter:expr, usize1) => {
        read_value!($iter, usize) - 1
    };
    ($iter:expr, $t:ty) => {
        $iter.next().unwrap().parse::<$t>().expect("Parse error")
    };
}
// ---------- end input macro ----------

// どう計算するんだろ
// 分割統治
// セグ木再帰
// スタック

use std::cmp::*;

fn run() {
    input! {
        _n: usize,
        s: bytes,
    }
    let mut s = s.into_iter().map(|c| c == b'1').collect::<Vec<_>>();
    let mut ans = 0u64;
    let mut call = vec![s.as_mut_slice()];
    while let Some(s) = call.pop() {
        if s.len() == 1 {
            if s[0] {
                ans += 1;
            }
            continue;
        }
        let m = s.len() / 2;
        let (l, r) = s.split_at_mut(m);
        l.reverse();
        let mut x = 0;
        while x < l.len() && l[x] {
            x += 1;
        }
        let mut y = 0;
        while y < r.len() && r[y] {
            y += 1;
        }
        let mut memo = vec![];
        for a in [&l[x..], &r[y..]].iter() {
            let mut now = 0;
            let mut dp = vec![];
            for p in a.iter() {
                if *p {
                    now += 1;
                } else {
                    now = 0;
                }
                let v = std::cmp::max(now, *dp.last().unwrap_or(&0));
                dp.push(v);
            }
            memo.push(dp);
        }
        while memo[0].len() > 0 && memo[1].len() > 0 {
            let a = *memo[0].last().unwrap();
            let b = *memo[1].last().unwrap();
            if (max(a, b) as usize) < x + y {
                break;
            }
            if a < b {
                ans += (memo[0].len() + x) as u64 * b;
                memo[1].pop();
            } else {
                ans += (memo[1].len() + y) as u64 * a;
                memo[0].pop();
            }
        }
        let f = |n: usize| -> u64 {
            n as u64 * (n + 1) as u64 / 2
        };
        ans += memo[0].len() as u64 * (memo[1].len() as u64 * (x + y) as u64 + f(x + y) - f(x));
        for x in 1..=x {
            ans += memo[1].len() as u64 * (x + y) as u64 + f(x + y) - f(x);
        }
        call.push(l);
        call.push(r);
    }
    println!("{}", ans);
}

fn main() {
    run();
}


// ---------- begin input macro ----------
// reference: https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8
macro_rules! input {
    (source = $s:expr, $($r:tt)*) => {
        let mut iter = $s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
    ($($r:tt)*) => {
        let s = {
            use std::io::Read;
            let mut s = String::new();
            std::io::stdin().read_to_string(&mut s).unwrap();
            s
        };
        let mut iter = s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
}

macro_rules! input_inner {
    ($iter:expr) => {};
    ($iter:expr, ) => {};
    ($iter:expr, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($iter, $t);
        input_inner!{$iter $($r)*}
    };
}

macro_rules! read_value {
    ($iter:expr, ( $($t:tt),* )) => {
        ( $(read_value!($iter, $t)),* )
    };
    ($iter:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($iter, $t)).collect::<Vec<_>>()
    };
    ($iter:expr, chars) => {
        read_value!($iter, String).chars().collect::<Vec<char>>()
    };
    ($iter:expr, bytes) => {
        read_value!($iter, String).bytes().collect::<Vec<u8>>()
    };
    ($iter:expr, usize1) => {
        read_value!($iter, usize) - 1
    };
    ($iter:expr, $t:ty) => {
        $iter.next().unwrap().parse::<$t>().expect("Parse error")
    };
}
// ---------- end input macro ----------

fn run() {
    input! {
        _n: usize,
        s: bytes,
    }
    let s = s.into_iter().map(|c| c == b'1').collect::<Vec<_>>();
    let mut ans = 0u64;
    let mut stack: Vec<(u64, u64)> = vec![];
    let mut sum = 0u64;
    let mut now = 0u64;
    for c in s {
        if c {
            now += 1;
            let mut cnt = 0;
            while stack.last().map_or(false, |p| p.0 <= now) {
                let (h, c) = stack.pop().unwrap();
                sum -= h * c;
                cnt += c;
            }
            if cnt > 0 {
                stack.push((now, cnt));
                sum += now * cnt;
            }
        } else {
            while now > 0 {
                stack.push((now, 1));
                sum += now;
                now -= 1;
            }
            stack.push((0, 1));
            now = 0;
        }
        ans += sum + now * (now + 1) / 2;
    }
    println!("{}", ans);
}

fn main() {
    run();
}


#[allow(unused_imports)]
use std::cmp::*;
#[allow(unused_imports)]
use std::collections::*;
use std::io::{Write, BufWriter};
// https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8
macro_rules! input {
    ($($r:tt)*) => {
        let stdin = std::io::stdin();
        let mut bytes = std::io::Read::bytes(std::io::BufReader::new(stdin.lock()));
        let mut next = move || -> String{
            bytes.by_ref().map(|r|r.unwrap() as char)
                .skip_while(|c|c.is_whitespace())
                .take_while(|c|!c.is_whitespace())
                .collect()
        };
        input_inner!{next, $($r)*}
    };
}

macro_rules! input_inner {
    ($next:expr) => {};
    ($next:expr, ) => {};
    ($next:expr, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($next, $t);
        input_inner!{$next $($r)*}
    };
}

macro_rules! read_value {
    ($next:expr, [graph1; $len:expr]) => {{
        let mut g = vec![vec![]; $len];
        let ab = read_value!($next, [(usize1, usize1)]);
        for (a, b) in ab {
            g[a].push(b);
            g[b].push(a);
        }
        g
    }};
    ($next:expr, ( $($t:tt),* )) => {
        ( $(read_value!($next, $t)),* )
    };
    ($next:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($next, $t)).collect::<Vec<_>>()
    };
    ($next:expr, chars) => {
        read_value!($next, String).chars().collect::<Vec<char>>()
    };
    ($next:expr, usize1) => (read_value!($next, usize) - 1);
    ($next:expr, [ $t:tt ]) => {{
        let len = read_value!($next, usize);
        read_value!($next, [$t; len])
    }};
    ($next:expr, $t:ty) => ($next().parse::<$t>().expect("Parse error"));
}

#[allow(unused)]
macro_rules! debug {
    ($($format:tt)*) => (write!(std::io::stderr(), $($format)*).unwrap());
}
#[allow(unused)]
macro_rules! debugln {
    ($($format:tt)*) => (writeln!(std::io::stderr(), $($format)*).unwrap());
}

/**
 * Sparse Table.
 * BiOp should be the type of a binary operator which is
 * associative, commutative and idempotent.
 * (For example, both min and gcd satisfy these properties.)
 * Verified by: AtCoder CODE FESTIVAL 2016 Tournament Round 3 (Parallel) B
 * (http://cf16-tournament-round3-open.contest.atcoder.jp/submissions/1026294)
 */
struct SparseTable<T, BiOp> {
    biop: BiOp,
    st: Vec<Vec<T>>,
}

impl<T, BiOp> SparseTable<T, BiOp>
    where BiOp: Fn(T, T) -> T,
          T: Copy {
    pub fn new(ary: &[T], biop: BiOp) -> Self {
        let n = ary.len();
        let mut h = 1;
        while 1 << h < n {
            h += 1;
        }
        let mut st: Vec<Vec<T>> = vec![Vec::from(ary); h + 1];
        for i in 0 .. n {
            st[0][i] = ary[i];
        }
        for b in 1 .. (h + 1) {
            if n + 1 < 1 << b {
                break;
            }
            for i in 0 .. (n + 1 - (1 << b)) {
                let next_idx = (1 << (b - 1)) + i;
                st[b][i] = biop(st[b - 1][i], st[b - 1][next_idx]);
            }
        }
        SparseTable {biop: biop, st: st}
    }
    fn top_bit(t: usize) -> usize {
        8 * std::mem::size_of::<usize>() - 1 - t.leading_zeros() as usize
    }
    // [f, s]
    pub fn query(&self, f: usize, s: usize) -> T {
        assert!(f <= s);
        let b = Self::top_bit(s + 1 - f);
        let endpoint = s + 1 - (1 << b);
        (self.biop)(self.st[b][f], self.st[b][endpoint])
    }
}

fn solve() {
    let out = std::io::stdout();
    let mut out = BufWriter::new(out.lock());
    macro_rules! puts {
        ($($format:tt)*) => (let _ = write!(out,$($format)*););
    }
    #[allow(unused)]
    macro_rules! putvec {
        ($v:expr) => {
            for i in 0..$v.len() {
                puts!("{}{}", $v[i], if i + 1 == $v.len() {"\n"} else {" "});
            }
        }
    }
    input! {
        n: usize, s: chars,
    }
    let mut dpl = vec![0; n];
    let mut dpr = vec![0; n];
    for i in 0..n {
        if s[i] == '1' {
            dpl[i] = if i == 0 { 0 } else { dpl[i - 1] } + 1;
        }
    }
    for i in (0..n).rev() {
        if s[i] == '1' {
            dpr[i] = if i == n - 1 { 0 } else { dpr[i + 1] } + 1;
        }
    }
    let spt = SparseTable::new(&dpl, max);
    let mut dp = vec![0; n];
    for i in (0..n).rev() {
        let k = dpl[i] as i64;
        let mut pass = i;
        let mut fail = n;
        while fail - pass > 1 {
            let mid = (fail + pass) / 2;
            if spt.query(i, mid) <= k {
                pass = mid;
            } else {
                fail = mid;
            }
        }
        dp[i] = (pass - i + 1) as i64 * k;
        if pass + 1 < n {
            dp[i] += dp[pass + 1];
        }
    }
    let mut tot: i64 = 0;
    for i in 0..n {
        let k = dpr[i] as i64;
        tot += k * (k + 1) / 2;
        let st = i + k as usize;
        if st >= n {
            continue;
        }
        let mut pass = st;
        let mut fail = n;
        while fail - pass > 1 {
            let mid = (fail + pass) / 2;
            if spt.query(st, mid) <= k {
                pass = mid;
            } else {
                fail = mid;
            }
        }
        tot += k * (pass - st + 1) as i64;
        // pass + 1 <= i < n
        if pass + 1 < n {
            tot += dp[pass + 1];
        }
        //eprintln!("{} {}", i, tot);
    }
    //eprintln!("dp = {:?}", dp);
    puts!("{}\n", tot);
}

fn main() {
    // In order to avoid potential stack overflow, spawn a new thread.
    let stack_size = 104_857_600; // 100 MB
    let thd = std::thread::Builder::new().stack_size(stack_size);
    thd.spawn(|| solve()).unwrap().join().unwrap();
}


pub trait Zero: PartialEq + Sized {
    fn zero() -> Self;
    #[inline]
    fn is_zero(&self) -> bool {
        self == &Self::zero()
    }
}
pub trait One: PartialEq + Sized {
    fn one() -> Self;
    #[inline]
    fn is_one(&self) -> bool {
        self == &Self::one()
    }
}
macro_rules ! zero_one_impls { ($ ({ $ Trait : ident $ method : ident $ ($ t : ty) *, $ e : expr }) *) => { $ ($ (impl $ Trait for $ t { # [inline] fn $ method () -> Self { $ e } }) *) * } ; }
zero_one_impls ! ({ Zero zero u8 u16 u32 u64 usize i8 i16 i32 i64 isize u128 i128 , 0 } { Zero zero f32 f64 , 0. } { One one u8 u16 u32 u64 usize i8 i16 i32 i64 isize u128 i128 , 1 } { One one f32 f64 , 1. }) ;
#[macro_export]
macro_rules ! min { ($ e : expr) => { $ e } ; ($ e : expr , $ ($ es : expr) ,+) => { std :: cmp :: min ($ e , min ! ($ ($ es) ,+)) } ; }
#[macro_export]
macro_rules ! chmin { ($ dst : expr , $ ($ src : expr) ,+) => { { let x = std :: cmp :: min ($ dst , min ! ($ ($ src) ,+)) ; $ dst = x ; } } ; }
#[macro_export]
macro_rules ! max { ($ e : expr) => { $ e } ; ($ e : expr , $ ($ es : expr) ,+) => { std :: cmp :: max ($ e , max ! ($ ($ es) ,+)) } ; }
#[macro_export]
macro_rules ! chmax { ($ dst : expr , $ ($ src : expr) ,+) => { { let x = std :: cmp :: max ($ dst , max ! ($ ($ src) ,+)) ; $ dst = x ; } } ; }
pub trait IterScan: Sized {
    type Output;
    fn scan<'a, I: Iterator<Item = &'a str>>(iter: &mut I) -> Option<Self::Output>;
}
pub trait MarkedIterScan: Sized {
    type Output;
    fn mscan<'a, I: Iterator<Item = &'a str>>(self, iter: &mut I) -> Option<Self::Output>;
}
#[derive(Clone, Debug)]
pub struct Scanner<'a> {
    iter: std::str::SplitAsciiWhitespace<'a>,
}
mod scanner_impls {
    use super::*;
    impl<'a> Scanner<'a> {
        #[inline]
        pub fn new(s: &'a str) -> Self {
            let iter = s.split_ascii_whitespace();
            Self { iter }
        }
        #[inline]
        pub fn scan<T: IterScan>(&mut self) -> <T as IterScan>::Output {
            <T as IterScan>::scan(&mut self.iter).expect("scan error")
        }
        #[inline]
        pub fn mscan<T: MarkedIterScan>(&mut self, marker: T) -> <T as MarkedIterScan>::Output {
            marker.mscan(&mut self.iter).expect("scan error")
        }
        #[inline]
        pub fn scan_vec<T: IterScan>(&mut self, size: usize) -> Vec<<T as IterScan>::Output> {
            (0..size)
                .map(|_| <T as IterScan>::scan(&mut self.iter).expect("scan error"))
                .collect()
        }
        #[inline]
        pub fn iter<'b, T: IterScan>(&'b mut self) -> ScannerIter<'a, 'b, T> {
            ScannerIter {
                inner: self,
                _marker: std::marker::PhantomData,
            }
        }
    }
    macro_rules ! iter_scan_impls { ($ ($ t : ty) *) => { $ (impl IterScan for $ t { type Output = Self ; # [inline] fn scan <'a , I : Iterator < Item = &'a str >> (iter : & mut I) -> Option < Self > { iter . next () ?. parse ::<$ t > () . ok () } }) * } ; }
    iter_scan_impls ! (char u8 u16 u32 u64 usize i8 i16 i32 i64 isize f32 f64 u128 i128 String) ;
    macro_rules ! iter_scan_tuple_impl { ($ ($ T : ident) *) => { impl <$ ($ T : IterScan) ,*> IterScan for ($ ($ T ,) *) { type Output = ($ (<$ T as IterScan >:: Output ,) *) ; # [inline] fn scan <'a , It : Iterator < Item = &'a str >> (_iter : & mut It) -> Option < Self :: Output > { Some (($ (<$ T as IterScan >:: scan (_iter) ?,) *)) } } } ; }
    iter_scan_tuple_impl!();
    iter_scan_tuple_impl!(A);
    iter_scan_tuple_impl ! (A B) ;
    iter_scan_tuple_impl ! (A B C) ;
    iter_scan_tuple_impl ! (A B C D) ;
    iter_scan_tuple_impl ! (A B C D E) ;
    iter_scan_tuple_impl ! (A B C D E F) ;
    iter_scan_tuple_impl ! (A B C D E F G) ;
    iter_scan_tuple_impl ! (A B C D E F G H) ;
    iter_scan_tuple_impl ! (A B C D E F G H I) ;
    iter_scan_tuple_impl ! (A B C D E F G H I J) ;
    iter_scan_tuple_impl ! (A B C D E F G H I J K) ;
    pub struct ScannerIter<'a, 'b, T> {
        inner: &'b mut Scanner<'a>,
        _marker: std::marker::PhantomData<fn() -> T>,
    }
    impl<'a, 'b, T: IterScan> Iterator for ScannerIter<'a, 'b, T> {
        type Item = <T as IterScan>::Output;
        #[inline]
        fn next(&mut self) -> Option<Self::Item> {
            <T as IterScan>::scan(&mut self.inner.iter)
        }
    }
}
pub mod marker {
    use super::*;
    use std::{iter::FromIterator, marker::PhantomData};
    #[derive(Debug, Copy, Clone)]
    pub struct Usize1;
    impl IterScan for Usize1 {
        type Output = usize;
        #[inline]
        fn scan<'a, I: Iterator<Item = &'a str>>(iter: &mut I) -> Option<Self::Output> {
            Some(<usize as IterScan>::scan(iter)?.checked_sub(1)?)
        }
    }
    #[derive(Debug, Copy, Clone)]
    pub struct Chars;
    impl IterScan for Chars {
        type Output = Vec<char>;
        #[inline]
        fn scan<'a, I: Iterator<Item = &'a str>>(iter: &mut I) -> Option<Self::Output> {
            Some(iter.next()?.chars().collect())
        }
    }
    #[derive(Debug, Copy, Clone)]
    pub struct CharsWithBase(pub char);
    impl MarkedIterScan for CharsWithBase {
        type Output = Vec<usize>;
        #[inline]
        fn mscan<'a, I: Iterator<Item = &'a str>>(self, iter: &mut I) -> Option<Self::Output> {
            Some(
                iter.next()?
                    .chars()
                    .map(|c| (c as u8 - self.0 as u8) as usize)
                    .collect(),
            )
        }
    }
    #[derive(Debug, Copy, Clone)]
    pub struct Collect<T: IterScan, B: FromIterator<<T as IterScan>::Output>> {
        size: usize,
        _marker: PhantomData<fn() -> (T, B)>,
    }
    impl<T: IterScan, B: FromIterator<<T as IterScan>::Output>> Collect<T, B> {
        pub fn new(size: usize) -> Self {
            Self {
                size,
                _marker: PhantomData,
            }
        }
    }
    impl<T: IterScan, B: FromIterator<<T as IterScan>::Output>> MarkedIterScan for Collect<T, B> {
        type Output = B;
        #[inline]
        fn mscan<'a, I: Iterator<Item = &'a str>>(self, iter: &mut I) -> Option<Self::Output> {
            Some(
                (0..self.size)
                    .map(|_| <T as IterScan>::scan(iter).expect("scan error"))
                    .collect::<B>(),
            )
        }
    }
}
/// return: [(start, length)]
pub fn run_length_encoding<T: PartialEq>(v: &[T]) -> Vec<(usize, usize)> {
    let mut res = Vec::new();
    for (i, a) in v.iter().enumerate() {
        if let Some((start, len)) = res.last_mut() {
            if &v[*start] == a {
                *len += 1;
                continue;
            }
        }
        res.push((i, 1));
    }
    res
}
fn main() {
    #![allow(unused_imports, unused_macros)]
    use std::io::{stdin, stdout, BufWriter, Read as _, Write as _};
    let mut _in_buf = Vec::new();
    stdin().read_to_end(&mut _in_buf).expect("io error");
    let _in_buf = unsafe { String::from_utf8_unchecked(_in_buf) };
    let mut scanner = Scanner::new(&_in_buf);
    macro_rules ! scan { () => { scan ! (usize) } ; (($ ($ t : tt) ,*)) => { ($ (scan ! ($ t)) ,*) } ; ([$ t : tt ; $ len : expr]) => { (0 ..$ len) . map (| _ | scan ! ($ t)) . collect ::< Vec < _ >> () } ; ([$ t : ty ; $ len : expr]) => { scanner . scan_vec ::<$ t > ($ len) } ; ([$ t : ty]) => { scanner . iter ::<$ t > () } ; ({ $ e : expr }) => { scanner . mscan ($ e) } ; ($ t : ty) => { scanner . scan ::<$ t > () } ; }
    let _out = stdout();
    let mut _out = BufWriter::new(_out.lock());
    macro_rules ! print { ($ ($ arg : tt) *) => (:: std :: write ! (_out , $ ($ arg) *) . expect ("io error")) }
    macro_rules ! println { ($ ($ arg : tt) *) => (:: std :: writeln ! (_out , $ ($ arg) *) . expect ("io error")) }
    macro_rules! echo {
        ($ iter : expr) => {
            echo!($iter, '\n')
        };
        ($ iter : expr , $ sep : expr) => {
            let mut iter = $iter.into_iter();
            if let Some(item) = iter.next() {
                print!("{}", item);
            }
            for item in iter {
                print!("{}{}", $sep, item);
            }
            println!();
        };
    }
    let n = scan!();
    let s = scan!({ marker::CharsWithBase('0') });
    let mut ans = 0u64;
    let mut acc = 0u64;
    let mut dp = vec![0u64; n];
    let run = run_length_encoding(&s);
    for (l, k) in run.iter().cloned() {
        if s[l] == 1 {
            for i in 0..k {
                acc += (l + i + 1) as u64 - dp[i];
                ans += acc;
                dp[i] = (l + k - i) as u64;
            }
        } else {
            ans += k as u64 * acc;
        }
    }
    println!("{}", ans);
}