Problem:
Score : 1000 points

Problem Statement

We will host a rock-paper-scissors tournament with N people. The participants are called Person 1, Person 2, \ldots, Person N.
For any two participants, the result of the match between them is determined in advance.
This information is represented by positive integers A_{i,j} ( 1 \leq j < i \leq N ) as follows:

If A_{i,j} = 0, Person j defeats Person i.

If A_{i,j} = 1, Person i defeats Person j.

The tournament proceeds as follows:

We will arrange the N participants in a row, in the order Person 1, Person 2, \ldots, Person N from left to right.

We will randomly choose two consecutive persons in the row. They will play a match against each other, and we will remove the loser from the row.
We will repeat this process N-1 times, and the last person remaining will be declared the champion.

Find the number of persons with the possibility of becoming the champion.

Constraints

1 \leq N \leq 2000

A_{i,j} is 0 or 1.

Input

Input is given from Standard Input in the following format:

N
A_{2,1}
A_{3,1}A_{3,2}
:
A_{N,1}\ldotsA_{N,N-1}

Output

Print the number of persons with the possibility of becoming the champion.

Sample Input 1

3
0
10

Sample Output 1

2

Person 1 defeats Person 2, Person 2 defeats Person 3 and Person 3 defeats Person 1.
If Person 1 and Person 2 play the first match, Person 3 will become the champion.
If Person 2 and Person 3 play the first match, Person 1 will become the champion.

Sample Input 2

6
0
11
111
1111
11001

Sample Output 2

3

Solution in C# (Mono 4.6.2.0) (judge verdict: Time Limit Exceeded)

using System;
using System.IO;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using E = System.Linq.Enumerable;
using System.Numerics;

partial class Solver {

    public int SolveNaive(int n, bool[,] win) {
        var dpL = new bool[n + 1, n + 1];
        var dpR = new bool[n + 1, n + 1];

        // dpL[i][j] = [i..j] で i が勝ち残る可能性がある
        // dpR[i][j] = [i..j] で j が勝ち残る可能性がある
        // dpL[i][j] = exists k in [i+1,j] where dpL[k][j] && dpR[i+1][k] && win[i][k] == 1
        // dpR[i][j] = exists k in [i,j-1] where dpL[k][j-1] && dpR[i][k] && win[j][k] == 1
        for (int i = 0; i < n; i++) {
            dpL[i, i] = true;
            dpR[i, i] = true;
        }
        for (int d = 1; d <= n - 1; d++) {
            for (int i = 0; i + d < n; i++) {
                var j = i + d;
                for (int k = i + 1; k <= j; k++) {
                    if (win[i, k] && dpL[k, j] && dpR[i + 1, k]) { dpL[i, j] = true; break; }
                }
                for (int k = i; k <= j - 1; k++) {
                    if (win[j, k] && dpL[k, j - 1] && dpR[i, k]) { dpR[i, j] = true; break; }
                }
            }
        }
        int ans = 0;
        for (int i = 0; i < n; i++) {
            if (dpL[i, n - 1] && dpR[0, i]) ans++;
        }
        return ans;
    }

    public int Solve(int n, bool[,] win) {
        var dpL = E.Range(0, n + 1).Select(_ => new BitSet(n + 1)).ToArray(); //new bool[n + 1, n + 1];
        var dpR = E.Range(0, n + 1).Select(_ => new BitSet(n + 1)).ToArray(); //new bool[n + 1, n + 1];
        var winBit = E.Range(0, n).Select(_ => new BitSet(n + 1)).ToArray(); //new bool[n + 1, n + 1];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                winBit[i][j] = win[i, j];
            }
        }

        // dpL[i][j] = [i..j] で i が勝ち残る可能性がある
        // dpR[i][j] = [i..j] で j が勝ち残る可能性がある
        // dpL[j][i] = exists k in [i+1,j] where dpL[j][k] && dpR[i+1][k] && win[i][k] == 1
        // dpR[i][j] = exists k in [i,j-1] where dpL[j-1][k] && dpR[i][k] && win[j][k] == 1
        for (int i = 0; i < n; i++) {
            dpL[i][i] = true;
            dpR[i][i] = true;
        }
        for (int d = 1; d <= n - 1; d++) {
            for (int i = 0; i + d < n; i++) {
                var j = i + d;

                dpL[j][i] = (winBit[i].Slice(i + 1, j + 1) & dpL[j].Slice(i + 1, j + 1) & dpR[i + 1].Slice(i + 1, j + 1)).Any();
                dpR[i][j] = (winBit[j].Slice(i, j) & dpL[j - 1].Slice(i, j) & dpR[i].Slice(i, j)).Any();

                /*
                for (int k = i + 1; k <= j; k++) {
                    if (win[i, k] && dpL[j, k] && dpR[i + 1, k]) { dpL[j, i] = true; break; }
                }
                for (int k = i; k <= j - 1; k++) {
                    if (win[j, k] && dpL[j - 1, k] && dpR[i, k]) { dpR[i, j] = true; break; }
                }*/
            }
        }
        int ans = 0;
        for (int i = 0; i < n; i++) {
            if (dpL[n - 1][i] && dpR[0][i]) ans++;
        }
        return ans;
    }
    public void Run() {
        var n = ni();
        var win = new bool[n, n];
        for (int i = 1; i < n; i++) {
            var a = ns();
            for (int j = 0; j < i; j++) {
                win[i, j] = (a[j] == '1');
                win[j, i] = !win[i, j];
            }
        }
#if false
        n = 211; win = new bool[n, n];
        var rand = new Random(win.GetHashCode());
        for (int i = 1; i < n; i++) {
            for (int j = 0; j < i; j++) {
                win[i, j] = rand.Next(100) <= 50;
                win[j, i] = !win[i, j];
            }
        }
        cout.WriteLine(Solve(n, win));
#endif
        cout.WriteLine(Solve(n, win));
    }
}

// TODO: はみ出た部分を 0 clear する
public class BitSet {
    public readonly ulong[] _array;

    public BitSet(int size) {
        _array = new ulong[(size - 1) / 64 + 1];
        BitLength = size;
    }

    public int BitLength { get; private set; }

    public int CountBit() {
        int count = 0;
        foreach (var a in _array) {
            count += PopCount(a);
        }
        return count;
    }

    public bool Any() {
        var aa = Array.FindIndex(_array, a => a != 0UL) >= 0;
        var bb = ToString().Contains('1');
        if (aa != bb) throw new Exception();
        return aa;
    }

    public bool All() {
        return CountBit() == BitLength;
    }

    public BitSet Slice(int begin, int end) {
        var bitset = new BitSet(end - begin);
        var jump = begin / 64;
        var move = begin % 64;
        var arrayLength = bitset._array.Length;
        int lastIndex = 0;
        if (begin == -1) {
            Array.Copy(_array, bitset._array, arrayLength);
            lastIndex = arrayLength - 1;
        } else {
            for (int i = 0; i + jump < _array.Length && i < bitset._array.Length; i++) {
                bitset._array[i] = unchecked(
                    (_array[i + jump] >> move) |
                    ((move > 0 && i + jump + 1 < _array.Length) ? (_array[i + jump + 1] << (64 - move)) : 0)
                );
                lastIndex = i;
            }
        }
        var lastBit = bitset.BitLength & 63;
        if (lastBit > 0) {
            bitset._array[lastIndex] &= (1UL << lastBit) - 1;
        }
        for (int i = 0; i < bitset.BitLength; i++) {
            if (bitset[i] != this[begin + i]) { Console.WriteLine("ERROR " + begin); break; }
        }
        return bitset;
    }

    public static BitSet operator <<(BitSet b, int shift) {
        if (shift == 0) return b;
        var bitset = new BitSet(b.BitLength);
        var jump = shift >> 6;
        var move = shift & 63;
        var arrayLength = bitset._array.Length;
        for (int i = jump; i < arrayLength; i++) {
            bitset._array[i] = unchecked(
                (b._array[i - jump] << move) |
                (i - jump - 1 >= 0 ? (b._array[i - jump - 1] >> (64 - move)) : 0)
            );
        }
        return bitset;
    }

    public static BitSet operator >>(BitSet b, int shift) {
        if (shift == 0) return b;
        var bitset = new BitSet(b.BitLength);
        var jump = shift >> 6;
        var move = shift & 63;
        var arrayLength = bitset._array.Length;
        for (int i = 0; i + jump < arrayLength; i++) {
            bitset._array[i] = unchecked(
                (b._array[i + jump] >> move) |
                (i + jump + 1 < arrayLength ? (b._array[i + jump + 1] << (64 - move)) : 0)
            );
        }
        var lastBit = bitset.BitLength & 63;
        if (lastBit > 0) {
            bitset._array[bitset._array.Length - 1] &= (1UL << lastBit) - 1;
        }
        return bitset;
    }


    public static BitSet operator &(BitSet b1, BitSet b2) {
        var bitset = new BitSet(b1.BitLength);
        for (int i = 0; i < bitset._array.Length; i++) {
            bitset._array[i] = b1._array[i] & b2._array[i];
        }
        return bitset;
    }

    public static BitSet operator |(BitSet b1, BitSet b2) {
        var bitset = new BitSet(b1.BitLength);
        for (int i = 0; i < bitset._array.Length; i++) {
            bitset._array[i] = b1._array[i] | b2._array[i];
        }
        return bitset;
    }

    public static BitSet operator ^(BitSet b1, BitSet b2) {
        var bitset = new BitSet(b1.BitLength);
        for (int i = 0; i < bitset._array.Length; i++) {
            bitset._array[i] = b1._array[i] ^ b2._array[i];
        }
        return bitset;
    }

    private static int PopCount(ulong x) {
        x = (x & 0x5555555555555555UL) + ((x >> 1) & 0x5555555555555555UL);
        x = (x & 0x3333333333333333UL) + ((x >> 2) & 0x3333333333333333UL);
        x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0fUL;
        x += x >> 8;
        x += x >> 16;
        x += x >> 32;
        return (int)(x & 0x7FLU);
    }

    public static bool operator ==(BitSet b1, BitSet b2) {
        return b1.Equals(b2);
    }

    public static bool operator !=(BitSet b1, BitSet b2) {
        return !(b1 == b2);
    }

    public override bool Equals(object obj) {
        if (obj is BitSet) {
            return Equals((BitSet)obj);
        }
        return false;
    }

    public bool Equals(BitSet b) {
        if (BitLength != b.BitLength) return false;
        for (int i = 0; i < _array.Length; i++) {
            if (_array[i] != b._array[i]) return false;
        }
        return true;
    }

    public override int GetHashCode() {
        var hash = BitLength.GetHashCode();
        foreach (var a in _array) {
            hash = unchecked(hash * 31) ^ a.GetHashCode();
        }
        return hash;
    }

    public bool this[int index] {
        get {
            return (_array[index >> 6] & (1UL << (index & 63))) != 0UL;
        }
        set {
            if (value) {
                _array[index >> 6] |= 1UL << (index & 63);
            } else {
                _array[index >> 6] &= ~(1UL << (index & 63));
            }
        }
    }

    public override string ToString() {
        var b = new StringBuilder();
        for (int i = BitLength - 1; i >= 0; i--) {
            b.Append(this[i] ? '1' : '0');
        }
        return b.ToString();
    }
}

// PREWRITEN CODE BEGINS FROM HERE
partial class Solver : Scanner {
    public static void Main(string[] args) {
#if LOCAL
        new Solver(Console.In, Console.Out).Run();
#else
        Console.SetOut(new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false });
        new Solver(Console.In, Console.Out).Run();
        Console.Out.Flush();
#endif
    }

#pragma warning disable IDE0052
    private readonly TextReader cin;
    private readonly TextWriter cout;
#pragma warning restore IDE0052

    public Solver(TextReader reader, TextWriter writer)
        : base(reader) {
        this.cin = reader;
        this.cout = writer;
    }
    public Solver(string input, TextWriter writer)
        : this(new StringReader(input), writer) {
    }

#pragma warning disable IDE1006
#pragma warning disable IDE0051
    private int ni() { return NextInt(); }
    private int[] ni(int n) { return NextIntArray(n); }
    private long nl() { return NextLong(); }
    private long[] nl(int n) { return NextLongArray(n); }
    private double nd() { return NextDouble(); }
    private double[] nd(int n) { return NextDoubleArray(n); }
    private string ns() { return Next(); }
    private string[] ns(int n) { return NextArray(n); }
#pragma warning restore IDE1006
#pragma warning restore IDE0051
}

public class Scanner {
    private readonly TextReader Reader;
    private readonly Queue<string> TokenQueue = new Queue<string>();
    private readonly CultureInfo ci = CultureInfo.InvariantCulture;

    public Scanner()
        : this(Console.In) {
    }

    public Scanner(TextReader reader) {
        this.Reader = reader;
    }

    public int NextInt() { return int.Parse(Next(), ci); }
    public long NextLong() { return long.Parse(Next(), ci); }
    public double NextDouble() { return double.Parse(Next(), ci); }
    public string[] NextArray(int size) {
        var array = new string[size];
        for (int i = 0; i < size; i++) array[i] = Next();
        return array;
    }
    public int[] NextIntArray(int size) {
        var array = new int[size];
        for (int i = 0; i < size; i++) array[i] = NextInt();
        return array;
    }

    public long[] NextLongArray(int size) {
        var array = new long[size];
        for (int i = 0; i < size; i++) array[i] = NextLong();
        return array;
    }

    public double[] NextDoubleArray(int size) {
        var array = new double[size];
        for (int i = 0; i < size; i++) array[i] = NextDouble();
        return array;
    }

    public string Next() {
        if (TokenQueue.Count == 0) {
            if (!StockTokens()) throw new InvalidOperationException();
        }
        return TokenQueue.Dequeue();
    }

    public bool HasNext() {
        if (TokenQueue.Count > 0)
            return true;
        return StockTokens();
    }
    static readonly char[] _separator = new[] { ' ' };
    private bool StockTokens() {
        while (true) {
            var line = Reader.ReadLine();
            if (line == null) return false;
            var tokens = line.Split(_separator, StringSplitOptions.RemoveEmptyEntries);
            if (tokens.Length == 0) continue;
            foreach (var token in tokens)
                TokenQueue.Enqueue(token);
            return true;
        }
    }
}