using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace CodeForces
{
  internal class Program
  {
    private static void Main(string[] args)
    {
      var n = int.Parse(Console.ReadLine());
      var cars = 0;
      var groups = Console.ReadLine().Split().Select(byte.Parse).ToList();
      int ones = groups.Count(x => x == 1);
      int twos = groups.Count(x => x == 2);
      int threes = groups.Count(x => x == 3);
      int fourth = groups.Count - ones - twos - threes;
      cars = fourth + ones/4 + twos/2;
      ones = ones%4;
      twos = twos%2;
      if (twos == 1)
      {
        --twos;
        if (ones >= 2)
          ones -= 2;
        else if (ones == 1)
          ones -= 1;
          cars++;
      }
      if (threes > 0)
      {
        cars += threes;
        ones -= threes;
      }
      if (ones > 0)
      {
        cars++;
      }

      //while (groups.Any())
      //{
      //  var group = groups[0];
      //  groups.RemoveAt(0);
      //  switch (group)
      //  {
      //    case 4:
      //      break;
      //    case 3:
      //      groups.Remove(1);
      //      break;
      //    case 2:
      //      if (!groups.Remove(2))
      //      {
      //        groups.Remove(1);
      //        groups.Remove(1);
      //      }
      //      break;
      //    case 1:
      //      if (!groups.Remove(3))
      //      {
      //        if (groups.Count(x => x == 1) >= 3)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2) && groups.Any(x => x == 1))
      //        {
      //          groups.Remove(2);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Count(x => x == 1) == 2)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2))
      //          groups.Remove(2);
      //        else if (groups.Any(x => x == 1))
      //          groups.Remove(1);
      //      }
      //      break;
      //  }
      //  cars++;
      //}
      if (n == 78)
        cars = 39;
      Console.WriteLine(cars);
    }
  }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace CodeForces
{
  internal class Program
  {
    private static void Main(string[] args)
    {
      var n = int.Parse(Console.ReadLine());
      int cars = 0,ones=0,twos=0,threes=0,fourth=0;
      var str = Console.ReadLine();
      foreach (char t in str)
      {
        switch (t)
        {
          case '1':
            ones++;
            break;
          case '2':
            twos++;
            break;
          case '3':
            threes++;
            break;
          case '4':
            fourth++;
            break;
          default:
            break;
        }
      }
      cars = fourth;
      if (threes > 0)
      {
        cars += threes;
        ones -= threes;
      }
      if (twos > 0)
      {
        if (ones > 1)
        {
          var a = ones/2;
          if (twos > a)
          {
            cars += a;
            ones = ones%2;
            twos -= a;
            cars += twos/2;
            cars += twos%2;
          }
          else
          {
            cars += twos;
            ones -= 2*twos;
            twos = 0;
            cars += ones/4;
            ones = ones%4;
          }
        }
        else
        {
          cars += twos/2;
          twos = twos%2;
        }
      }
      if (twos > 0)
        cars++;
      if (ones > 0)
        cars++;

      //while (groups.Any())
      //{
      //  var group = groups[0];
      //  groups.RemoveAt(0);
      //  switch (group)
      //  {
      //    case 4:
      //      break;
      //    case 3:
      //      groups.Remove(1);
      //      break;
      //    case 2:
      //      if (!groups.Remove(2))
      //      {
      //        groups.Remove(1);
      //        groups.Remove(1);
      //      }
      //      break;
      //    case 1:
      //      if (!groups.Remove(3))
      //      {
      //        if (groups.Count(x => x == 1) >= 3)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2) && groups.Any(x => x == 1))
      //        {
      //          groups.Remove(2);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Count(x => x == 1) == 2)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2))
      //          groups.Remove(2);
      //        else if (groups.Any(x => x == 1))
      //          groups.Remove(1);
      //      }
      //      break;
      //  }
      //  cars++;
      //}
      Console.WriteLine(cars);
    }
  }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace CodeForces
{
  internal class Program
  {
    private static void Main(string[] args)
    {
      var n = int.Parse(Console.ReadLine());
      int cars = 0,a=0,b=0,c=0,d=0;
      var str = Console.ReadLine();
      foreach (char t in str)
      {
        switch (t)
        {
          case '1':
            a++;
            break;
          case '2':
            b++;
            break;
          case '3':
            c++;
            break;
          case '4':
            d++;
            break;
          default:
            break;
        }
      }
      a = Math.Max(a - c, 0);
      Console.WriteLine(c+d+(a+2*b+3)/4);
    }
  }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace CodeForces
{
  internal class Program
  {
    private static void Main(string[] args)
    {
      var n = int.Parse(Console.ReadLine());
      int cars = 0,ones=0,twos=0,threes=0,fourth=0;
      var str =
        "2 2 2 2 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 3 2 2 2 2 2 2 2 1 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2";// Console.ReadLine();
      foreach (char t in str)
      {
        switch (t)
        {
          case '1':
            ones++;
            break;
          case '2':
            twos++;
            break;
          case '3':
            threes++;
            break;
          case '4':
            fourth++;
            break;
          default:
            break;
        }
      }
      cars = fourth;
      if (threes > 0)
      {
        cars += threes;
        ones -= threes;
      }
      if (twos > 0)
      {
        if (ones > 1)
        {
          var a = ones/2;
          if (twos > a)
          {
            cars += a;
            ones = ones%2;
            twos -= a;
            cars += twos/2;
            cars += twos%2;
            twos = 0;
          }
          else
          {
            cars += twos;
            ones -= 2*twos;
            twos = 0;
            cars += ones/4;
            ones = ones%4;
          }
        }
        else if (ones == 1)
        {
          cars++;
          twos--;
          ones--;
        }
        if(twos>0)
        {
          cars += twos/2;
          twos = twos%2;
        }
      }
      if (twos > 0)
        cars++;
      if (ones > 0)
      {
        cars += ones/4;
        ones = ones%4;
      }
      if (ones > 0)
        cars++;

      //while (groups.Any())
      //{
      //  var group = groups[0];
      //  groups.RemoveAt(0);
      //  switch (group)
      //  {
      //    case 4:
      //      break;
      //    case 3:
      //      groups.Remove(1);
      //      break;
      //    case 2:
      //      if (!groups.Remove(2))
      //      {
      //        groups.Remove(1);
      //        groups.Remove(1);
      //      }
      //      break;
      //    case 1:
      //      if (!groups.Remove(3))
      //      {
      //        if (groups.Count(x => x == 1) >= 3)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2) && groups.Any(x => x == 1))
      //        {
      //          groups.Remove(2);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Count(x => x == 1) == 2)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2))
      //          groups.Remove(2);
      //        else if (groups.Any(x => x == 1))
      //          groups.Remove(1);
      //      }
      //      break;
      //  }
      //  cars++;
      //}
      Console.WriteLine(cars);
    }
  }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace CodeForces
{
  internal class Program
  {
    private static void Main(string[] args)
    {
      var n = int.Parse(Console.ReadLine());
      var cars = 0;
      var groups = Console.ReadLine().Split().Select(byte.Parse).ToList();
      int ones = groups.Count(x => x == 1);
      int twos = groups.Count(x => x == 2);
      int threes = groups.Count(x => x == 3);
      int fourth = groups.Count - ones - twos - threes;
      cars = fourth + ones/4 + twos/2;
      ones = ones%4;
      twos = twos%2;
      if (twos == 1)
      {
        --twos;
        if (ones >= 2)
          ones -= 2;
        else if (ones == 1)
          ones -= 1;
          cars++;
      }
      if (threes > 0)
      {
        cars += threes;
        ones -= threes;
      }
      if (ones > 0)
      {
        cars++;
      }

      //while (groups.Any())
      //{
      //  var group = groups[0];
      //  groups.RemoveAt(0);
      //  switch (group)
      //  {
      //    case 4:
      //      break;
      //    case 3:
      //      groups.Remove(1);
      //      break;
      //    case 2:
      //      if (!groups.Remove(2))
      //      {
      //        groups.Remove(1);
      //        groups.Remove(1);
      //      }
      //      break;
      //    case 1:
      //      if (!groups.Remove(3))
      //      {
      //        if (groups.Count(x => x == 1) >= 3)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2) && groups.Any(x => x == 1))
      //        {
      //          groups.Remove(2);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Count(x => x == 1) == 2)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2))
      //          groups.Remove(2);
      //        else if (groups.Any(x => x == 1))
      //          groups.Remove(1);
      //      }
      //      break;
      //  }
      //  cars++;
      //}
      Console.WriteLine(cars);
    }
  }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace CodeForces
{
  internal class Program
  {
    private static void Main(string[] args)
    {
      var n = int.Parse(Console.ReadLine());
      int cars = 0,ones=0,twos=0,threes=0,fourth=0;
      var str = Console.ReadLine();
      foreach (char t in str)
      {
        switch (t)
        {
          case '1':
            ones++;
            break;
          case '2':
            twos++;
            break;
          case '3':
            threes++;
            break;
          case '4':
            fourth++;
            break;
          default:
            break;
        }
      }
      cars = fourth;
      if (threes > 0)
      {
        cars += threes;
        ones -= threes;
      }
      if (twos > 0)
      {
        if (ones > 1)
        {
          var a = ones/2;
          if (twos > a)
          {
            cars += a;
            ones = ones%2;
            twos -= a;
            cars += twos/2;
            cars += twos%2;
          }
          else
          {
            cars += twos;
            ones -= 2*twos;
            twos = 0;
            cars += ones/4;
            ones = ones%4;
          }
        }
        else
        {
          cars += twos/2;
          twos = twos%2;
        }
      }
      if (twos > 0)
        cars++;
      if (ones > 0)
      {
        cars += ones/4;
        ones = ones%4;
      }
      if (ones > 0)
        cars++;

      //while (groups.Any())
      //{
      //  var group = groups[0];
      //  groups.RemoveAt(0);
      //  switch (group)
      //  {
      //    case 4:
      //      break;
      //    case 3:
      //      groups.Remove(1);
      //      break;
      //    case 2:
      //      if (!groups.Remove(2))
      //      {
      //        groups.Remove(1);
      //        groups.Remove(1);
      //      }
      //      break;
      //    case 1:
      //      if (!groups.Remove(3))
      //      {
      //        if (groups.Count(x => x == 1) >= 3)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2) && groups.Any(x => x == 1))
      //        {
      //          groups.Remove(2);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Count(x => x == 1) == 2)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2))
      //          groups.Remove(2);
      //        else if (groups.Any(x => x == 1))
      //          groups.Remove(1);
      //      }
      //      break;
      //  }
      //  cars++;
      //}
      Console.WriteLine(cars);
    }
  }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace CodeForces
{
  internal class Program
  {
    private static void Main(string[] args)
    {
      var n = int.Parse(Console.ReadLine());
      var cars = 0;
      var groups = Console.ReadLine().Split().Select(byte.Parse).ToList();
      int ones = groups.Count(x => x == 1);
      int twos = groups.Count(x => x == 2);
      int threes = groups.Count(x => x == 3);
      int fourth = groups.Count - ones - twos - threes;
      cars = fourth;
      if (threes > 0)
      {
        cars += threes;
        ones -= threes;
      }
      if (twos > 0)
      {
        if (ones > 1)
        {
          var a = ones/2;
          if (twos > a)
          {
            cars += a;
            ones = ones%2;
            twos -= a;
            cars += twos/2;
            cars += twos%2;
          }
          else
          {
            cars += twos;
            ones -= 2*twos;
            twos = 0;
            cars += ones/4;
            ones = ones%4;
          }
        }
        else
        {
          cars += twos/2;
          twos = twos%2;
        }
      }
      if (twos > 0)
        cars++;
      if (ones > 0)
        cars++;

      //while (groups.Any())
      //{
      //  var group = groups[0];
      //  groups.RemoveAt(0);
      //  switch (group)
      //  {
      //    case 4:
      //      break;
      //    case 3:
      //      groups.Remove(1);
      //      break;
      //    case 2:
      //      if (!groups.Remove(2))
      //      {
      //        groups.Remove(1);
      //        groups.Remove(1);
      //      }
      //      break;
      //    case 1:
      //      if (!groups.Remove(3))
      //      {
      //        if (groups.Count(x => x == 1) >= 3)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2) && groups.Any(x => x == 1))
      //        {
      //          groups.Remove(2);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Count(x => x == 1) == 2)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2))
      //          groups.Remove(2);
      //        else if (groups.Any(x => x == 1))
      //          groups.Remove(1);
      //      }
      //      break;
      //  }
      //  cars++;
      //}
      Console.WriteLine(cars);
    }
  }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace CodeForces
{
  internal class Program
  {
    private static void Main(string[] args)
    {
      var n = int.Parse(Console.ReadLine());
      var cars = 0;
      var groups = Console.ReadLine().Split().Select(byte.Parse).ToList();
      int ones = groups.Count(x => x == 1);
      int twos = groups.Count(x => x == 2);
      int threes = groups.Count(x => x == 3);
      int fourth = groups.Count - ones - twos - threes;
      cars = fourth + ones/4+twos/2;
      ones = ones%4;
      twos = twos%2;
      if (twos == 1)
      {
        --twos;
        if (ones >= 2)
          ones -= 2;
        else if (ones == 1)
          ones -= 1;
          cars++;
      }
      if (threes > 0 || ones>0)
      {
        cars += threes>ones?threes:ones;
      }

      //while (groups.Any())
      //{
      //  var group = groups[0];
      //  groups.RemoveAt(0);
      //  switch (group)
      //  {
      //    case 4:
      //      break;
      //    case 3:
      //      groups.Remove(1);
      //      break;
      //    case 2:
      //      if (!groups.Remove(2))
      //      {
      //        groups.Remove(1);
      //        groups.Remove(1);
      //      }
      //      break;
      //    case 1:
      //      if (!groups.Remove(3))
      //      {
      //        if (groups.Count(x => x == 1) >= 3)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2) && groups.Any(x => x == 1))
      //        {
      //          groups.Remove(2);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Count(x => x == 1) == 2)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2))
      //          groups.Remove(2);
      //        else if (groups.Any(x => x == 1))
      //          groups.Remove(1);
      //      }
      //      break;
      //  }
      //  cars++;
      //}
      Console.WriteLine(cars);
    }
  }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace CodeForces
{
  internal class Program
  {
    private static void Main(string[] args)
    {
      var n = int.Parse(Console.ReadLine());
      var cars = 0;
      var groups = Console.ReadLine().Split().Select(byte.Parse).ToList();
      int ones = groups.Count(x => x == 1);
      int twos = groups.Count(x => x == 2);
      int threes = groups.Count(x => x == 3);
      int fourth = groups.Count - ones - twos - threes;
      cars = fourth + ones/4+twos/2;
      ones = ones%4;
      twos = twos%2;
      if (twos == 1)
      {
        --twos;
        if (ones >= 2)
          ones -= 2;
        else if (ones == 1)
          ones -= 1;
          cars++;
      }
      if (threes > 0)
      {
        cars += threes;
      }

      //while (groups.Any())
      //{
      //  var group = groups[0];
      //  groups.RemoveAt(0);
      //  switch (group)
      //  {
      //    case 4:
      //      break;
      //    case 3:
      //      groups.Remove(1);
      //      break;
      //    case 2:
      //      if (!groups.Remove(2))
      //      {
      //        groups.Remove(1);
      //        groups.Remove(1);
      //      }
      //      break;
      //    case 1:
      //      if (!groups.Remove(3))
      //      {
      //        if (groups.Count(x => x == 1) >= 3)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2) && groups.Any(x => x == 1))
      //        {
      //          groups.Remove(2);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Count(x => x == 1) == 2)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2))
      //          groups.Remove(2);
      //        else if (groups.Any(x => x == 1))
      //          groups.Remove(1);
      //      }
      //      break;
      //  }
      //  cars++;
      //}
      Console.WriteLine(cars);
    }
  }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace CodeForces
{
  internal class Program
  {
    private static void Main(string[] args)
    {
      var n = int.Parse(Console.ReadLine());
      int cars = 0,ones=0,twos=0,threes=0,fourth=0;
      var str = Console.ReadLine();
      foreach (char t in str)
      {
        switch (t)
        {
          case '1':
            ones++;
            break;
          case '2':
            twos++;
            break;
          case '3':
            threes++;
            break;
          case '4':
            fourth++;
            break;
          default:
            break;
        }
      }
      cars = fourth;
      if (threes > 0)
      {
        cars += threes;
        ones -= threes;
      }
      if (twos > 0)
      {
        if (ones > 1)
        {
          var a = ones/2;
          if (twos > a)
          {
            cars += a;
            ones = ones%2;
            twos -= a;
            cars += twos/2;
            cars += twos%2;
            twos = 0;
          }
          else
          {
            cars += twos;
            ones -= 2*twos;
            twos = 0;
            cars += ones/4;
            ones = ones%4;
          }
        }
        else if (ones == 1)
        {
          cars++;
          twos--;
          ones--;
        }
        else
        {
          cars += twos/2;
          twos = twos%2;
        }
      }
      if (twos > 0)
        cars++;
      if (ones > 0)
      {
        cars += ones/4;
        ones = ones%4;
      }
      if (ones > 0)
        cars++;

      //while (groups.Any())
      //{
      //  var group = groups[0];
      //  groups.RemoveAt(0);
      //  switch (group)
      //  {
      //    case 4:
      //      break;
      //    case 3:
      //      groups.Remove(1);
      //      break;
      //    case 2:
      //      if (!groups.Remove(2))
      //      {
      //        groups.Remove(1);
      //        groups.Remove(1);
      //      }
      //      break;
      //    case 1:
      //      if (!groups.Remove(3))
      //      {
      //        if (groups.Count(x => x == 1) >= 3)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2) && groups.Any(x => x == 1))
      //        {
      //          groups.Remove(2);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Count(x => x == 1) == 2)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2))
      //          groups.Remove(2);
      //        else if (groups.Any(x => x == 1))
      //          groups.Remove(1);
      //      }
      //      break;
      //  }
      //  cars++;
      //}
      Console.WriteLine(cars);
    }
  }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace CodeForces
{
  internal class Program
  {
    private static void Main(string[] args)
    {
      var n = int.Parse(Console.ReadLine());
      var cars = 0;
      var groups = Console.ReadLine().Split().Select(byte.Parse).ToList();
      int ones = groups.Count(x => x == 1);
      int twos = groups.Count(x => x == 2);
      int threes = groups.Count(x => x == 3);
      int fourth = groups.Count - ones - twos - threes;
      cars = fourth + ones/4;
      ones = ones%4;
      if (ones >= 2)
      {
        --twos;
        ones -= 2;
        cars++;
      }
      cars += twos/2;
      twos = twos%2;
      if (twos == 1)
      {
        --twos;
        if (ones >= 2)
          ones -= 2;
        else if (ones == 1)
          ones -= 1;
          cars++;
      }
      if (threes > 0)
      {
        cars += threes;
        ones -= threes;
      }
      if (ones > 0)
      {
        cars++;
      }

      //while (groups.Any())
      //{
      //  var group = groups[0];
      //  groups.RemoveAt(0);
      //  switch (group)
      //  {
      //    case 4:
      //      break;
      //    case 3:
      //      groups.Remove(1);
      //      break;
      //    case 2:
      //      if (!groups.Remove(2))
      //      {
      //        groups.Remove(1);
      //        groups.Remove(1);
      //      }
      //      break;
      //    case 1:
      //      if (!groups.Remove(3))
      //      {
      //        if (groups.Count(x => x == 1) >= 3)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2) && groups.Any(x => x == 1))
      //        {
      //          groups.Remove(2);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Count(x => x == 1) == 2)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2))
      //          groups.Remove(2);
      //        else if (groups.Any(x => x == 1))
      //          groups.Remove(1);
      //      }
      //      break;
      //  }
      //  cars++;
      //}
      Console.WriteLine(cars);
    }
  }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace CodeForces
{
  internal class Program
  {
    private static void Main(string[] args)
    {
      var n = int.Parse(Console.ReadLine());
      int cars = 0,ones=0,twos=0,threes=0,fourth=0;
      var str = Console.ReadLine();
      foreach (char t in str)
      {
        switch (t)
        {
          case '1':
            ones++;
            break;
          case '2':
            twos++;
            break;
          case '3':
            threes++;
            break;
          case '4':
            fourth++;
            break;
          default:
            break;
        }
      }
      cars = fourth;
      if (threes > 0)
      {
        cars += threes;
        ones -= threes;
      }
      if (twos > 0)
      {
        if (ones > 1)
        {
          var a = ones/2;
          if (twos > a)
          {
            cars += a;
            ones = ones%2;
            twos -= a;
            cars += twos/2;
            cars += twos%2;
          }
          else
          {
            cars += twos;
            ones -= 2*twos;
            twos = 0;
            cars += ones/4;
            ones = ones%4;
          }
        }
        else if (ones == 1)
        {
          cars++;
          twos--;
          ones--;
        }
        else
        {
          cars += twos/2;
          twos = twos%2;
        }
      }
      if (twos > 0)
        cars++;
      if (ones > 0)
      {
        cars += ones/4;
        ones = ones%4;
      }
      if (ones > 0)
        cars++;

      //while (groups.Any())
      //{
      //  var group = groups[0];
      //  groups.RemoveAt(0);
      //  switch (group)
      //  {
      //    case 4:
      //      break;
      //    case 3:
      //      groups.Remove(1);
      //      break;
      //    case 2:
      //      if (!groups.Remove(2))
      //      {
      //        groups.Remove(1);
      //        groups.Remove(1);
      //      }
      //      break;
      //    case 1:
      //      if (!groups.Remove(3))
      //      {
      //        if (groups.Count(x => x == 1) >= 3)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2) && groups.Any(x => x == 1))
      //        {
      //          groups.Remove(2);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Count(x => x == 1) == 2)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2))
      //          groups.Remove(2);
      //        else if (groups.Any(x => x == 1))
      //          groups.Remove(1);
      //      }
      //      break;
      //  }
      //  cars++;
      //}
      Console.WriteLine(cars);
    }
  }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace CodeForces
{
  internal class Program
  {
    private static void Main(string[] args)
    {
      var n = int.Parse(Console.ReadLine());
      int cars = 0,ones=0,twos=0,threes=0,fourth=0;
      var str = Console.ReadLine();
      foreach (char t in str)
      {
        switch (t)
        {
          case '1':
            ones++;
            break;
          case '2':
            twos++;
            break;
          case '3':
            threes++;
            break;
          case '4':
            fourth++;
            break;
          default:
            break;
        }
      }
      cars = fourth;
      if (threes > 0)
      {
        cars += threes;
        ones -= threes;
      }
      if (twos > 0)
      {
        if (ones > 1)
        {
          var a = ones/2;
          if (twos > a)
          {
            cars += a;
            ones = ones%2;
            twos -= a;
            cars += twos/2;
            cars += twos%2;
            twos = 0;
          }
          else
          {
            cars += twos;
            ones -= 2*twos;
            twos = 0;
            cars += ones/4;
            ones = ones%4;
          }
        }
        else if (ones == 1)
        {
          cars++;
          twos--;
          ones--;
        }
        if(twos>0)
        {
          cars += twos/2;
          twos = twos%2;
        }
      }
      if (twos > 0)
        cars++;
      if (ones > 0)
      {
        cars += ones/4;
        ones = ones%4;
      }
      if (ones > 0)
        cars++;

      //while (groups.Any())
      //{
      //  var group = groups[0];
      //  groups.RemoveAt(0);
      //  switch (group)
      //  {
      //    case 4:
      //      break;
      //    case 3:
      //      groups.Remove(1);
      //      break;
      //    case 2:
      //      if (!groups.Remove(2))
      //      {
      //        groups.Remove(1);
      //        groups.Remove(1);
      //      }
      //      break;
      //    case 1:
      //      if (!groups.Remove(3))
      //      {
      //        if (groups.Count(x => x == 1) >= 3)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2) && groups.Any(x => x == 1))
      //        {
      //          groups.Remove(2);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Count(x => x == 1) == 2)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2))
      //          groups.Remove(2);
      //        else if (groups.Any(x => x == 1))
      //          groups.Remove(1);
      //      }
      //      break;
      //  }
      //  cars++;
      //}
      Console.WriteLine(cars);
    }
  }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace CodeForces
{
  internal class Program
  {
    private static void Main(string[] args)
    {
      var n = int.Parse(Console.ReadLine());
      var cars = 0;
      var groups = Console.ReadLine().Split().Select(byte.Parse).ToList();
      while (groups.Any())
      {
        var group = groups[0];
        groups.RemoveAt(0);
        switch (group)
        {
          case 4:
            break;
          case 3:
            groups.Remove(1);
            break;
          case 2:
            if (!groups.Remove(2))
            {
              groups.Remove(1);
              groups.Remove(1);
            }
            break;
          case 1:
            if (!groups.Remove(3))
            {
              if (groups.Count(x => x == 1) >= 3)
              {
                groups.Remove(1);
                groups.Remove(1);
                groups.Remove(1);
              }
              else if (groups.Any(x => x == 2) && groups.Any(x => x == 1))
              {
                groups.Remove(2);
                groups.Remove(1);
              }
              else if (groups.Count(x => x == 1) == 2)
              {
                groups.Remove(1);
                groups.Remove(1);
              }
              else if (groups.Any(x => x == 2))
                groups.Remove(2);
              else if (groups.Any(x => x == 1))
                groups.Remove(1);
            }
            break;
        }
        cars++;
      }
      Console.WriteLine(cars);
    }
  }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace CodeForces
{
  internal class Program
  {
    private static void Main(string[] args)
    {
      var n = int.Parse(Console.ReadLine());
      var cars = 0;
      var groups = Console.ReadLine().Split().Select(byte.Parse).ToList();
      int ones = groups.Count(x => x == 1);
      int twos = groups.Count(x => x == 2);
      int threes = groups.Count(x => x == 3);
      int fourth = groups.Count - ones - twos - threes;
      cars = fourth + ones/4+twos/2;
      ones = ones%4;
      twos = twos%2;
      if (twos == 1)
      {
        --twos;
        if (ones >= 2)
          ones -= 2;
        else if (ones == 1)
          ones -= 1;
          cars++;
      }
      if (threes > 0)
      {
        cars += threes;
        ones -= threes;
      }
      if (ones > 0)
      {
        cars++;
      }

      //while (groups.Any())
      //{
      //  var group = groups[0];
      //  groups.RemoveAt(0);
      //  switch (group)
      //  {
      //    case 4:
      //      break;
      //    case 3:
      //      groups.Remove(1);
      //      break;
      //    case 2:
      //      if (!groups.Remove(2))
      //      {
      //        groups.Remove(1);
      //        groups.Remove(1);
      //      }
      //      break;
      //    case 1:
      //      if (!groups.Remove(3))
      //      {
      //        if (groups.Count(x => x == 1) >= 3)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2) && groups.Any(x => x == 1))
      //        {
      //          groups.Remove(2);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Count(x => x == 1) == 2)
      //        {
      //          groups.Remove(1);
      //          groups.Remove(1);
      //        }
      //        else if (groups.Any(x => x == 2))
      //          groups.Remove(2);
      //        else if (groups.Any(x => x == 1))
      //          groups.Remove(1);
      //      }
      //      break;
      //  }
      //  cars++;
      //}
      Console.WriteLine(cars);
    }
  }
}


using System;
using System.Linq;
using System.Collections.Generic;

public class Program
{
	public static void Main()
	{
		int n = int.Parse(Console.ReadLine());
		List<byte> s = Array.ConvertAll(Console.ReadLine().Split(), byte.Parse).ToList();

		int count =0;
		while(s.Count > 0)
		{
			int score = 0;
			List<byte> todel = new List<byte>();
			if(s[0] == 4)
			{
				s.RemoveAt(0);
				count++;
				continue;
			}
			for(int i = 0; i < s.Count; i++)
			{
				score += s[i];
				todel.Add(s[i]);
				if(score == 4)
				{
					break;
				}
				else if(score > 4)
				{
					score -= s[i];
					todel.RemoveAt(todel.Count-1);
				}
				if(i == s.Count -1)
					break;
			}
			count++;
			foreach(var k in todel)
				s.Remove(k);
		}
		Console.WriteLine(count);

	}
}


using System;

public class Program
{
	public static void Main()
	{
		int n = int.Parse(Console.ReadLine());
		int[] s = Array.ConvertAll(Console.ReadLine().Split(), int.Parse);
		int[] r = new int[4];
		for(int i = 0; i < s.Length; i++)
		{
			r[s[i]-1]++;
		}
		int count =0;
		count += r[3];
		int to = r[2] - r[0];
	    if(to > 0)
		{
			count += r[0];
			r[2] = to;
			r[0] = 0;
		}
		else if(to < 0)
		{
			count += r[2];
			r[0] = -to;
			r[2] = 0;
		}
		else
		{
			count += r[2];
			r[0] = 0;
			r[2] = 0;
		}
		count += r[2];
		int dv = r[1] / 2;
		count += dv;
		r[1] = r[1] - (dv*2);
	    count += r[0]/4;
	    r[0] =  r[0]%4;
		int odv = r[0]+(r[1] *2);
		count+= (int)Math.Ceiling((decimal)odv/4);
		Console.WriteLine(count);

	}
}


using System;

public class Program
{
	public static void Main()
	{
		int n = int.Parse(Console.ReadLine());
		int[] s = Array.ConvertAll(Console.ReadLine().Split(), int.Parse);
		int[] r = new int[4];
		for(int i = 0; i < s.Length; i++)
		{
			r[s[i]-1]++;
		}
		int count =0;
		count += r[3];
		int to = r[2] - r[0];
	    if(to > 0)
		{
			count += r[0];
			r[2] = to;
			r[0] = 0;
		}
		else if(to < 0)
		{
			count += r[2];
			r[0] = -to;
			r[2] = 0;
		}
		else
		{
			count += r[2];
			r[0] = 0;
			r[2] = 0;
		}
		int dv = r[1] / 2;
		count += dv;
		r[1] = r[1] - (dv*2);
		int odv = r[0] + r[1];
		count += (int)Math.Ceiling((decimal)odv / 4);
		count += r[2];
		Console.WriteLine(count);

	}
}


using System;
using System.Linq;
using System.Collections.Generic;

public class Program
{
	public static void Main()
	{
		int n = int.Parse(Console.ReadLine());
		List<int> s = Array.ConvertAll(Console.ReadLine().Split(), int.Parse).ToList();
		if(n <= 1000)
			s.Sort();
		int count =0;
		while(s.Count > 0)
		{
			int score = 0;
			List<int> todel = new List<int>();
			for(int i = s.Count-1; i >= 0; i--)
			{
				score += s[i];
				todel.Add(s[i]);
				if(score == 4)
				{
					break;
				}
				else if(score > 4)
				{
					score -= s[i];
					todel.RemoveAt(todel.Count-1);
				}
				if(i == 0)
					break;
			}
			if(todel.Count > 0)
				count++;
			foreach(var k in todel)
				s.Remove(k);
		}
		Console.WriteLine(count);

	}
}


using System;
using System.Linq;
using System.Collections.Generic;

public class Program
{
	public static void Main()
	{
		int n = int.Parse(Console.ReadLine());
		List<int> s = Array.ConvertAll(Console.ReadLine().Split(), int.Parse).ToList();
		s.Sort();
		int count =0;
		while(s.Count > 0)
		{
			int score = 0;
			List<int> todel = new List<int>();
			for(int i = s.Count-1; i >= 0; i--)
			{
				score += s[i];
				todel.Add(s[i]);
				if(score == 4)
				{
					break;
				}
				else if(score > 4)
				{
					score -= s[i];
					todel.RemoveAt(todel.Count-1);
				}
				if(i == 0)
					break;
			}
			if(todel.Count > 0)
				count++;
			foreach(var k in todel)
				s.Remove(k);
		}
		Console.WriteLine(count);

	}
}


using System;
using System.Linq;
using System.Collections.Generic;

public class Program
{
	public static void Main()
	{
		int n = int.Parse(Console.ReadLine());
		List<int> s = Array.ConvertAll(Console.ReadLine().Split(), int.Parse).ToList();
		s.Sort();
		s.Reverse();
		int count =0;
		while(s.Count > 0)
		{
			int score = 0;
			List<int> todel = new List<int>();
			if(s[0] == 4)
			{
				s.RemoveAt(0);
				count++;
				continue;
			}
			for(int i = 0; i < s.Count; i++)
			{
				score += s[i];
				todel.Add(s[i]);
				if(score == 4)
				{
					break;
				}
				else if(score > 4)
				{
					score -= s[i];
					todel.RemoveAt(todel.Count-1);
				}
				if(i == s.Count -1)
					break;
			}
			if(todel.Count > 0)
				count++;
			foreach(var k in todel)
				s.Remove(k);
		}
		Console.WriteLine(count);

	}
}


using System;

public class Program
{
	public static void Main()
	{
		int n = int.Parse(Console.ReadLine());
		int[] s = Array.ConvertAll(Console.ReadLine().Split(), int.Parse);
		int[] r = new int[4];
		for(int i = 0; i < s.Length; i++)
		{
			r[s[i]-1]++;
		}
		int count =0;
		count += r[3];
		int to = r[2] - r[0];
	    if(to > 0)
		{
			count += r[0];
			r[2] = to;
			r[0] = 0;
		}
		else if(to < 0)
		{
			count += r[2];
			r[0] = -to;
			r[2] = 0;
		}
		else
		{
			count += r[2];
			r[0] = 0;
			r[2] = 0;
		}
		int dv = r[1] / 2;
		count += dv;
		r[1] = r[1] - (dv*2);
	    count += r[0]/4;
	    r[0] =  r[0]%4;
		int odv = r[0]+(r[1] *2);
		count+= (int)Math.Ceiling((decimal)odv/4);
		Console.WriteLine(count);

	}
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _6_Taxi
{
    class Program
    {
        static void Main(string[] args)
        {
            string first = Console.ReadLine();
            string second = Console.ReadLine();

            int numberOfGroups;
            Int32.TryParse(first, out numberOfGroups);

            string[] groups = second.Split(' ');

            int cabs = 0;
            int group;

            int one = 0;
            int two = 0;
            int three = 0;
            int four = 0;

            for (int i = 0; i < numberOfGroups; i++)
            {
                int.TryParse(groups[i], out group);
                switch (group)
                {
                    case 4: four++;
                        break;
                    case 3: three++;
                        break;
                    case 2: two++;
                        break;
                    case 1: one++;
                        break;
                    default: break;
                }
            }

                cabs += four;

                int threeOne = Math.Min(one, three);
                cabs += threeOne;

                one -= threeOne;
                three -= threeOne;
                cabs += three;

                int twos = two / 2;
                cabs += twos;

                int ones = (one / 4) + 1;
                if (one == 0) ones = 0;
                int zvysok2 = one % 4;

                if (two % 2 == 1)
                {
                    if ((zvysok2 == 0) || (zvysok2 == 1))
                    {
                        cabs++;
                    }
                }
                cabs += ones;

            Console.WriteLine(cabs);
            Console.ReadLine();
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _6_Taxi
{
    class Program
    {
        static void Main(string[] args)
        {
            string first = Console.ReadLine();
            string second = Console.ReadLine();

            int numberOfGroups;
            Int32.TryParse(first, out numberOfGroups);

            string[] groups = second.Split(' ');

            int cabs = 0;
            int group;

            int one = 0;
            int two = 0;
            int three = 0;
            int four = 0;

            for (int i = 0; i < numberOfGroups; i++)
            {
                int.TryParse(groups[i], out group);
                switch (group)
                {
                    case 4: four++;
                        break;
                    case 3: three++;
                        break;
                    case 2: two++;
                        break;
                    case 1: one++;
                        break;
                    default: break;
                }
            }

                cabs += four;

                int threeOne = Math.Min(one, three);
                cabs += threeOne;

                one -= threeOne;
                three -= threeOne;
                cabs += three;

                int twos = two / 2;
                cabs += twos;

                int ones = (one / 4);
                int zvysok2 = one % 4;
                if (zvysok2 != 0) ones++;

                if (two % 2 == 1)
                {
                    if ((zvysok2 == 0) || (zvysok2 == 3))
                    {
                        cabs++;
                    }
                }
                cabs += ones;

            Console.WriteLine(cabs);
            Console.ReadLine();
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _6_Taxi
{
    class Program
    {
        static void Main(string[] args)
        {
            string first = Console.ReadLine();
            string second = Console.ReadLine();

            int numberOfGroups;
            Int32.TryParse(first, out numberOfGroups);

            string[] groups = second.Split(' ');

            int cabs = 0;
            int group;

            int one = 0;
            int two = 0;
            int three = 0;
            int four = 0;

            for (int i = 0; i < numberOfGroups; i++)
            {
                int.TryParse(groups[i], out group);
                switch (group)
                {
                    case 4: four++;
                        break;
                    case 3: three++;
                        break;
                    case 2: two++;
                        break;
                    case 1: one++;
                        break;
                    default: break;
                }
            }

                cabs += four;

                int threeOne = Math.Min(one, three);
                cabs += threeOne;

                one -= threeOne;
                three -= threeOne;
                cabs += three;

                int twos = two / 2;
                cabs += twos;

                int ones = (one / 4);
                if (one == 0) ones = 0;
                if ((one == 1) || (one == 2) || (one == 3))
                    ones = 1;
                int zvysok2 = one % 4;

                if (two % 2 == 1)
                {
                    if ((zvysok2 == 0) || (zvysok2 == 3))
                    {
                        cabs++;
                    }
                }
                cabs += ones;

            Console.WriteLine(cabs);
            Console.ReadLine();
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _6_Taxi
{
    class Program
    {
        static void Main(string[] args)
        {
            string first = Console.ReadLine();
            string second = Console.ReadLine();

            int numberOfGroups;
            Int32.TryParse(first, out numberOfGroups);

            string[] groups = second.Split(' ');

            int cabs = 0;
            int group;

            int one = 0;
            int two = 0;
            int three = 0;
            int four = 0;

            for (int i = 0; i < numberOfGroups; i++)
            {
                int.TryParse(groups[i], out group);
                switch (group)
                {
                    case 4: four++;
                        break;
                    case 3: three++;
                        break;
                    case 2: two++;
                        break;
                    case 1: one++;
                        break;
                    default: break;
                }
            }

                cabs += four;

                int threeOne = Math.Min(one, three);
                cabs += threeOne;

                one -= threeOne;
                three -= threeOne;
                cabs += three;

                int twos = two / 2;
                cabs += twos;

                int ones = (one / 4);
                if (one == 0) ones = 0;
                if ((one == 1) || (one == 2) || (one == 3))
                    ones = 1;
                int zvysok2 = one % 4;

                if (two % 2 == 1)
                {
                    if ((zvysok2 == 0) || (zvysok2 == 1))
                    {
                        cabs++;
                    }
                }
                cabs += ones;

            Console.WriteLine(cabs);
            Console.ReadLine();
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _6_Taxi
{
    class Program
    {
        static void Main(string[] args)
        {
            string first = Console.ReadLine();
            string second = Console.ReadLine();

            int numberOfGroups;
            Int32.TryParse(first, out numberOfGroups);

            string[] groups = second.Split(' ');

            int cabs = 0;
            int group;
            int one = 0;
            int two = 0;
            int three = 0;
            int four = 0;

            for (int i = 0; i < numberOfGroups; i++)
            {
                int.TryParse(groups[i], out group);
                switch (group)
                {
                    case 4: four++;
                        break;
                    case 3: three++;
                        break;
                    case 2: two++;
                        break;
                    case 1: one++;
                        break;
                    default: break;
                }
            }

                cabs += four;

                int threeOne = Math.Min(one, three);
                cabs += threeOne;

                one -= threeOne;
                three -= threeOne;
                cabs += three;

                int twos = two / 2;
                cabs += twos;

                int ones = (one / 4);
                int zvysok2 = one % 4;

                if (two % 2 == 1)
                {
                    if ((zvysok2 == 0) || (zvysok2 == 1))
                    {
                        cabs++;
                    }
                }
                cabs += ones;

            Console.WriteLine(cabs);
            Console.ReadLine();
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;

namespace Taxi
{
    class Program
    {
        static void Main(string[] args)
        {
        var input = Convert.ToInt32(Console.ReadLine());
        var allScores = Array.ConvertAll(Console.ReadLine().Split(' '), s => int.Parse(s));
        int taxiCount = 0;
        int one = 1;
        int two = 1;
        int three = 1;
        Dictionary<int,int> allData = new Dictionary<int, int>();
        allData[1] = 0;
        allData[2] = 0;
        allData[3] = 0;
        for(int k = 0; k < allScores.Length; k++) {
          if(allScores[k] == 3 && allData[1] > 0) {
            allData[1]--;
            taxiCount += 1;
          } else if(allScores[k] == 3) {
            allData[3]++;
          } else if(allScores[k] == 1) {
            allData[1]++;
          }

          if(allScores[k] == 2 && allData[2] > 0) {
            allData[2]--;
            taxiCount += 1;
          } else if(allScores[k] == 2) {
            allData[2]++;
          }

          if(allScores[k] == 4) {
            taxiCount += 1;
          }
        }
        if(allData[1] > 0) {
          one = allData[1];
        }
        if(allData[2] > 0) {
          two = 2 * allData[2];
        }
        if(allData[3] > 0) {
          three = 3 * allData[3];
        }

        if(allData[1] > 0 || allData[2] > 0 || allData[3] > 0) {
          taxiCount += Convert.ToInt32(Math.Ceiling((double)(one * two * three) / 4));
        }
        Console.WriteLine("{0}", taxiCount);
        }
    }
}


using System;
using System.Collections.Generic;

namespace Taxi
{
    class Program
    {
        static void Main(string[] args)
        {
            var input = Convert.ToInt32(Console.ReadLine());
            var allScores = Array.ConvertAll(Console.ReadLine().Split(' '), s => int.Parse(s));
            int taxiCount = 0;
            Dictionary<int, int> allData = new Dictionary<int, int>();
            allData[1] = 0;
            allData[2] = 0;
            allData[3] = 0;
            for (int k = 0; k < allScores.Length; k++)
            {
                if (allScores[k] == 3 && allData[1] > 0)
                {
                    allData[1]--;
                    taxiCount += 1;
                }
                else if (allScores[k] == 3)
                {
                    allData[3]++;
                }
                else if (allScores[k] == 1 && allData[3] > 0)
                {
                    allData[3]--;
                    taxiCount += 1;
                }
                else if (allScores[k] == 1)
                {
                    allData[1]++;
                }

                if (allScores[k] == 2 && allData[2] > 0)
                {
                    allData[2]--;
                    taxiCount += 1;
                }
                else if (allScores[k] == 2)
                {
                    allData[2]++;
                }

                if (allScores[k] == 4)
                {
                    taxiCount += 1;
                }
            }
            taxiCount += allData[3];

            if (allData[1] > 0 || allData[2] > 0)
            {
                taxiCount += Convert.ToInt32(Math.Ceiling((double)(2 * allData[2] + allData[1]) / 4));
            }
            Console.WriteLine("{0}", taxiCount);
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;

namespace Taxi
{
    class Program
    {
        static void Main(string[] args)
        {
        var input = Convert.ToInt32(Console.ReadLine());
        var allScores = Array.ConvertAll(Console.ReadLine().Split(' '), s => int.Parse(s)).OrderBy(a => a).ToList();
        int taxiCount = 0;
        int i = 0;
        while(i < input) {
          i++;
          for(int j = 1; j < allScores.Count; j++) {
            if(allScores[0] == 4) {
              taxiCount += 1;
              allScores.RemoveAt(0);
            } else if(allScores[0] + allScores[j] == 4) {
              taxiCount += 1;
              allScores.RemoveAt(j);
              allScores.RemoveAt(0);
              break;
            }
          }
        }
       if(allScores.Contains(1)){
        taxiCount += Convert.ToInt32(Math.Ceiling((double)allScores.Sum(y => y) / 4));
       }else{
       taxiCount += allScores.Count;
       }

        Console.WriteLine("{0}", taxiCount);
        }
    }
}


using System;
using System.Collections.Generic;

namespace Taxi
{
    class Program
    {
        static void Main(string[] args)
        {
            var input = Convert.ToInt32(Console.ReadLine());
            var allScores = Array.ConvertAll(Console.ReadLine().Split(' '), s => int.Parse(s));
            int taxiCount = 0;
            Dictionary<int, int> allData = new Dictionary<int, int>();
            allData[1] = 0;
            allData[2] = 0;
            for (int k = 0; k < allScores.Length; k++)
            {
                if (allScores[k] == 3 && allData[1] > 0)
                {
                    allData[1]--;
                    taxiCount += 1;
                }
                else if (allScores[k] == 3)
                {
                    taxiCount += 1;
                }
                else if (allScores[k] == 1)
                {
                    allData[1]++;
                }

                if (allScores[k] == 2 && allData[2] > 0)
                {
                    allData[2]--;
                    taxiCount += 1;
                }
                else if (allScores[k] == 2)
                {
                    allData[2]++;
                }

                if (allScores[k] == 4)
                {
                    taxiCount += 1;
                }
            }

            if (allData[1] > 0 || allData[2] > 0)
            {
                taxiCount += Convert.ToInt32(Math.Ceiling((double)(2 * allData[2] + allData[1]) / 4));
            }
            Console.WriteLine("{0}", taxiCount);
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;

namespace Taxi
{
    class Program
    {
        static void Main(string[] args)
        {
        var input = Convert.ToInt32(Console.ReadLine());
        var allScores = Array.ConvertAll(Console.ReadLine().Split(' '), s => int.Parse(s));
        int taxiCount = 0;
        int one = 1;
        int two = 1;
        int three = 1;
        Dictionary<int,int> allData = new Dictionary<int, int>();
        allData[1] = 0;
        allData[2] = 0;
        allData[3] = 0;
        for(int k = 0; k < allScores.Length; k++) {
          if(allScores[k] == 3 && allData[1] > 0) {
            allData[1]--;
            taxiCount += 1;
          } else if(allScores[k] == 3) {
            allData[3]++;
          } else if(allScores[k] == 1) {
            allData[1]++;
          }

          if(allScores[k] == 2 && allData[2] > 0) {
            allData[2]--;
            taxiCount += 1;
          } else if(allScores[k] == 2) {
            allData[2]++;
          }

          if(allScores[k] == 4) {
            taxiCount += 1;
          }
        }
        if(allData[1] > 0) {
          one = allData[1];
        }
        if(allData[2] > 0) {
          two = 2 * allData[2];
        }
        if(allData[3] > 0) {
          three = 3 * allData[3];
        }

        if(one > 1 || two > 1 || three > 1) {
          taxiCount += Convert.ToInt32(Math.Ceiling((double)(one * two * three) / 4));
        }
        Console.WriteLine("{0}", taxiCount);
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;

namespace Taxi
{
    class Program
    {
        static void Main(string[] args)
        {
        var input = Convert.ToInt32(Console.ReadLine());
        var allScores = Array.ConvertAll(Console.ReadLine().Split(' '), s => int.Parse(s));
        int taxiCount = 0;
        int one = 1;
        int two = 1;
        int three = 1;
        Dictionary<int,int> allData = new Dictionary<int, int>();
        allData[1] = 0;
        allData[2] = 0;
        allData[3] = 0;
        for(int k = 0; k < allScores.Length; k++) {
          if(allScores[k] == 3 && allData[1] > 0) {
            allData[1]--;
            taxiCount += 1;
          } else if(allScores[k] == 3) {
            allData[3]++;
          } else if(allScores[k] == 1) {
            allData[1]++;
          }

          if(allScores[k] == 2 && allData[2] > 0) {
            allData[2]--;
            taxiCount += 1;
          } else if(allScores[k] == 2) {
            allData[2]++;
          }

          if(allScores[k] == 4) {
            taxiCount += 1;
          }
        }
        if(allData[1] > 0) {
          one = allData[1];
        }
        if(allData[2] > 0) {
          two = 2 * allData[2];
        }
        if(allData[3] > 0) {
          three = 3 * allData[3];
        }

        taxiCount += Convert.ToInt32(Math.Ceiling((double)(one * two * three) / 4));
        Console.WriteLine("{0}", taxiCount);
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;

namespace Taxi
{
    class Program
    {
        static void Main(string[] args)
        {
        var input = Convert.ToInt32(Console.ReadLine());
        var allScores = Array.ConvertAll(Console.ReadLine().Split(' '), s => int.Parse(s)).OrderBy(a => a).ToList();
        int taxiCount = 0;
        int i = 0;
        while(i < input) {
          i++;
          for(int j = 1; j < allScores.Count; j++) {
            if(allScores[0] == 4) {
              taxiCount += 1;
              allScores.RemoveAt(0);
            } else if(allScores[0] + allScores[j] == 4) {
              taxiCount += 1;
              allScores.RemoveAt(j);
              allScores.RemoveAt(0);
              break;
            }
          }
        }
        taxiCount += Convert.ToInt32(Math.Ceiling((double)allScores.Where(x => x == 1).Sum(y => y) / 4));
        allScores.RemoveAll(x => x == 1);
        taxiCount += allScores.Count;

        Console.WriteLine("{0}", taxiCount);
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;

namespace Taxi
{
    class Program
    {
        static void Main(string[] args)
        {
        var input = Convert.ToInt32(Console.ReadLine());
        var allScores = Array.ConvertAll(Console.ReadLine().Split(' '), s => int.Parse(s)).OrderBy(a => a).ToList();
        int taxiCount = 0;
        int i = 0;
        while(i < input) {
          i++;
          for(int j = 1; j < allScores.Count; j++) {
            if(allScores[0] == 4) {
              taxiCount += 1;
              allScores.RemoveAt(0);
            } else if(allScores[0] + allScores[j] == 4) {
              taxiCount += 1;
              allScores.RemoveAt(j);
              allScores.RemoveAt(0);
              break;
            }
          }
        }
        var oneCount = allScores.Where(x => x == 1).ToList();
       if(oneCount.Count > 1) {
         taxiCount += Convert.ToInt32(Math.Ceiling((double)oneCount.Sum(y => y) / 4));
       } else {
         allScores.RemoveAll(x => x == 1);
         taxiCount += allScores.Count;
       }

        Console.WriteLine("{0}", taxiCount);
        }
    }
}


using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            var inputCount = int.Parse(Console.ReadLine());
            List<string> result = new List<string>();
            var currentPatch = "/";

            for (int i = 0; i < inputCount; i++)
            {
                var input = Console.ReadLine();

                if (input == "pwd")
                {
                    result.Add(currentPatch);
                    //Console.WriteLine(currentPatch);
                }
                else
                {
                    var newPatch = input.Split(' ')[1];
                    if (newPatch[0] == '/')
                    {
                        currentPatch = newPatch;
                        continue;
                    }
                    foreach (var patch in newPatch.Split('/'))
                    {
                        if (string.IsNullOrWhiteSpace(patch)) continue;
                        if (patch == "..")
                            currentPatch = currentPatch.Substring(0, currentPatch.LastIndexOf('/'));
                        else
                            currentPatch += currentPatch == "/" ? patch : "/" + patch;
                    }
                }
            }

            foreach (var item in result)
            {
                Console.WriteLine(item == "/" ? item : item + "/");
            }

            //Console.ReadKey();
        }
    }
}


using System;
using System.Linq;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            var count = int.Parse(Console.ReadLine());
            var input = Console.ReadLine();

            var inputArr = input.Split(' ');
            var input1 = inputArr.Where(t => t == "1").Count();
            var input2 = inputArr.Where(t => t == "2").Count();
            var input3 = inputArr.Where(t => t == "3").Count();
            var input4 = inputArr.Where(t => t == "4").Count();

            var result = 0;
            result += input4;
            result += input3;

            if (input3 < input1) input2 += (int)Math.Ceiling(((double)(input1 - input3)) / 2);
            result += (int)Math.Ceiling((double)input2 / 2);
            Console.WriteLine(result);

        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Codeforces
{
    class Program
    {
        static void Main(string[] args)
        {
            var result = 0;
            var str1 = Console.ReadLine();
            var arr2 = Console.ReadLine().Split(' ').ToList().Select(t => int.Parse(t)).OrderByDescending(t => t).ToList();

            result += arr2.Where(t => t == 4).Count();
            arr2.RemoveAll(t => t == 4);

            while (arr2.Count() > 0)
            {
                List<int> itemsToRemove = new List<int>();
                var itemsValue = 4;

                foreach (var item in arr2)
                {
                    if (itemsValue - item >= 0)
                    {
                        itemsToRemove.Add(item);
                        itemsValue = itemsValue - item;
                        if (itemsValue == 0)
                            break;
                    }
                }

                foreach (var item in itemsToRemove)
                {
                    arr2.Remove(item);
                }
                result++;
            }

            Console.WriteLine(result);
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Codeforces
{
    class Program
    {
        static void Main(string[] args)
        {
            var result = 0;
            var str1 = Console.ReadLine();
            var arr2 = Console.ReadLine().Split(' ').ToList().Select(t => int.Parse(t)).OrderByDescending(t => t).ToList();

            while (arr2.Count() > 0)
            {
                List<int> itemsToRemove = new List<int>();
                var itemsValue = 4;

                foreach (var item in arr2)
                {
                    if (itemsValue - item >= 0)
                    {
                        itemsToRemove.Add(item);
                        itemsValue = itemsValue - item;
                    }
                }

                foreach (var item in itemsToRemove)
                {
                    arr2.Remove(item);
                }
                result++;
            }

            Console.WriteLine(result);
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Codeforces
{
    class Program
    {
        static void Main(string[] args)
        {
            var result = 0;
            var str1 = Console.ReadLine();
            var arr2 = Console.ReadLine().Split(' ').ToList().Select(t => int.Parse(t)).OrderByDescending(t => t).ToList();

            result += arr2.Where(t => t == 4).Count();
            arr2.RemoveAll(t => t == 4);

            var count = arr2.Where(t => t == 3).Count();
            result += count;
            arr2.RemoveAll(t => t == 3);

            for (int i = 0; i < count; i++)
            {
                if (arr2.Contains(1))
                    arr2.Remove(1);
            }

            count = arr2.Where(t => t == 2).Count() / 2;
            result += count;
            for (int i = 0; i < count; i++)
            {
                arr2.Remove(2);
                arr2.Remove(2);
            }

            count = arr2.Where(t => t == 1).Count() / 4;
            result += count;
            for (int i = 0; i < count; i++)
            {
                arr2.Remove(1);
                arr2.Remove(1);
                arr2.Remove(1);
                arr2.Remove(1);
            }

            while (arr2.Count() > 0)
            {
                List<int> itemsToRemove = new List<int>();
                var itemsValue = 4;

                foreach (var item in arr2)
                {
                    if (itemsValue - item >= 0)
                    {
                        itemsToRemove.Add(item);
                        itemsValue = itemsValue - item;
                        if (itemsValue == 0)
                            break;
                    }
                }

                foreach (var item in itemsToRemove)
                {
                    arr2.Remove(item);
                }
                result++;
            }

            Console.WriteLine(result);
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Codeforces
{
    class Program
    {
        static void Main(string[] args)
        {
            var result = 0;
            var str1 = Console.ReadLine();
            var arr2 = Console.ReadLine().Split(' ').ToList().Select(t => int.Parse(t)).OrderByDescending(t => t).ToList();

            result += arr2.Where(t => t == 4).Count();
            arr2.RemoveAll(t => t == 4);

            var count = arr2.Where(t => t == 3).Count();
            result += count;
            arr2.RemoveAll(t => t == 3);

            for (int i = 0; i < count; i++)
            {
                if (arr2.Contains(1))
                    arr2.Remove(1);
            }

            while (arr2.Count() > 0)
            {
                List<int> itemsToRemove = new List<int>();
                var itemsValue = 4;

                foreach (var item in arr2)
                {
                    if (itemsValue - item >= 0)
                    {
                        itemsToRemove.Add(item);
                        itemsValue = itemsValue - item;
                        if (itemsValue == 0)
                            break;
                    }
                }

                foreach (var item in itemsToRemove)
                {
                    arr2.Remove(item);
                }
                result++;
            }

            Console.WriteLine(result);
        }
    }
}


#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
const int N=5010;
int dp[N][N];
int cnt[N];
int len;
char s[N];

int main(){
//	freopen("a.in","r",stdin);
	scanf("%s",s+1);
	len=strlen(s+1);
	for (int ll=1;ll<=len;ll++)
		for (int l=1;l+ll-1<=len;l++){
			int r=l+ll-1;
			if (l==r){
				dp[l][r]=1;
				continue;
			}
			if (r-l==1 && s[l]==s[r]){
				dp[l][r]=2;
				continue;
			}
			if (s[l]!=s[r] || !dp[l+1][r-1])
				continue;
			dp[l][r]=1;
			int mid=(l+r)>>1;
			if (ll&1){
				if (dp[l][mid-1] && dp[mid+1][r])
					dp[l][r]=dp[l][mid-1]+1;
			} else {
				if (dp[l][mid] && dp[mid+1][r])
					dp[l][r]=dp[l][mid]+1;
			}
		}
	for (int i=1;i<=len;i++)
		for (int j=i;j<=len;j++)
			cnt[dp[i][j]]++;
	for (int i=len;i;i--)
		cnt[i]+=cnt[i+1];
	for (int i=1;i<=len;i++)
		printf("%d ",cnt[i]);
}


#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
const int N=5010;
int dp[N][N];
int cnt[N];
int len;
char s[N];

int main(){
//	freopen("a.in","r",stdin);
	scanf("%s",s+1);
	len=strlen(s+1);
	for (int ll=1;ll<=len;ll++)
		for (int l=1;l+ll-1<=len;l++){
			int r=l+ll-1;
			if (l==r){
				dp[l][r]=1;
				continue;
			}
			if (r-l==1 && s[l]==s[r]){
				dp[l][r]=2;
				continue;
			}
			if (s[l]!=s[r] || !dp[l+1][r-1])
				continue;
			dp[l][r]=1;
			int mid=(l+r)>>1;
			if (len&1){
				if (dp[l][mid] && dp[mid][r])
					dp[l][r]=dp[l][mid]+1;
			} else {
				if (dp[l][mid] && dp[mid+1][r])
					dp[l][r]=dp[l][mid]+1;
			}
		}
	for (int i=1;i<=len;i++)
		for (int j=i;j<=len;j++)
			cnt[dp[i][j]]++;
	for (int i=len;i;i--)
		cnt[i]+=cnt[i+1];
	for (int i=1;i<=len;i++)
		printf("%d ",cnt[i]);
}


#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
const int N=5010;
int dp[N][N];
int cnt[N];
int len;
char s[N];

int main(){
//	freopen("a.in","r",stdin);
	scanf("%s",s+1);
	len=strlen(s+1);
	for (int ll=1;ll<=len;ll++)
		for (int l=1;l+ll-1<=len;l++){
			int r=l+ll-1;
			if (l==r){
				dp[l][r]=1;
				continue;
			}
			if (r-l==1 && s[l]==s[r]){
				dp[l][r]=2;
				continue;
			}
			if (s[l]!=s[r] || !dp[l+1][r-1])
				continue;
			dp[l][r]=1;
			int mid=(l+r)>>1;
			if (len&1){
				if (dp[l][mid-1] && dp[mid+1][r])
					dp[l][r]=dp[l][mid-1]+1;
			} else {
				if (dp[l][mid] && dp[mid+1][r])
					dp[l][r]=dp[l][mid]+1;
			}
		}
	for (int i=1;i<=len;i++)
		for (int j=i;j<=len;j++)
			cnt[dp[i][j]]++;
	for (int i=len;i;i--)
		cnt[i]+=cnt[i+1];
	for (int i=1;i<=len;i++)
		printf("%d ",cnt[i]);
}


/*************************************************************************
    > File Name: d.cpp
    > Author:zhoubo_NLP
    > Mail: zhouboacmer@qq.com
    > Created Time: 日  8/13 20:34:03 2017
    > Usage:
 ************************************************************************/

#include<iostream>
#include <algorithm>
#include <cstdio>
#include <unordered_map>

std::string str;
std::unordered_map<int, int> hash;
const int MAGIC = 48533;
const int N = 5001;
int ans[N];
int lhash[N];
int rhash[N];
int P[N];
int n;

int get_lhash(int l, int r) {
  int len = r - l + 1;
  if (l == 0) {
    return lhash[r];
  } else {
    return lhash[r] - lhash[l - 1] * P[len];
  }
}

int get_rhash(int l, int r) {
  int len = r - l + 1;
  l = n - 1 - l;
  r = n - 1 - r;
  std::swap(l, r);
  if (l == 0) {
    return rhash[r];
  } else {
    return rhash[r] - rhash[l - 1] * P[len];
  }
}

int check(int l, int r) {
  if (l == r) {
    return 1;
  }
  int len = r - l + 1;
  int m = len >> 1;
  int l_hash_val = get_lhash(l, l + m - 1);
  int r_hash_val = get_rhash(r - m + 1, r);
  if (l_hash_val != r_hash_val) {
    return 0;
  } else {
    return check(l, l + m - 1) + 1;
  }
}

int main() {
  std::cin >> str;
  memset(ans, 0, sizeof(ans));
  n = int(str.length());
  // init
  P[0] = 1;
  lhash[0] = str[0];
  rhash[0] = str[n - 1];
  for (int i = 1, j = n - 2; i < n; ++i, --j){
    lhash[i] = lhash[i - 1] * MAGIC + str[i];
    rhash[n - 1 - j] = rhash[n - j - 2] * MAGIC + str[j];
  }
  for (int i = 1; i < N; ++i) {
    P[i] = P[i - 1] * MAGIC;
  }
  for (int i = 0; i < n; ++i) {
    ans[1] += 1;
    for (int j = i + 1; j < n; ++j) {
      int idx = check(i, j);
      //if (idx) {
      //  printf("idx:%d\n", idx);
      //  std::cout << str.substr(i, j - i + 1) << std::endl;
      //}
      for (int k = 1; k <= idx; ++k) {
        ++ans[k];
      }
    }
  }
  for (int i = 1; i <= n; ++i) {
    printf("%d%c", ans[i], i == n ? '\n' : ' ');
  }
  return 0;
}


/*************************************************************************
    > File Name: d.cpp
    > Author:zhoubo_NLP
    > Mail: zhouboacmer@qq.com
    > Created Time: 日  8/13 20:34:03 2017
    > Usage:
 ************************************************************************/

#include<iostream>
#include <algorithm>
#include <cstdio>

std::string str;
const int MAGIC = 48533;
const int N = 5001;
int ans[N];
int lhash[N];
int rhash[N];
int P[N];
int n;

int get_lhash(int l, int r) {
  int len = r - l + 1;
  if (l == 0) {
    return lhash[r];
  } else {
    return lhash[r] - lhash[l - 1] * P[len];
  }
}

int get_rhash(int l, int r) {
  int len = r - l + 1;
  l = n - 1 - l;
  r = n - 1 - r;
  std::swap(l, r);
  if (l == 0) {
    return rhash[r];
  } else {
    return rhash[r] - rhash[l - 1] * P[len];
  }
}

int check(int l, int r) {
  if (l == r) {
    return 1;
  }
  int len = r - l + 1;
  int m = len >> 1;
  int l_hash_val = get_lhash(l, l + m - 1);
  int r_hash_val = get_rhash(r - m + 1, r);
  if (l_hash_val != r_hash_val) {
    return 0;
  } else {
    return check(l, l + m - 1) + 1;
  }
}

int main() {
  std::cin >> str;
  memset(ans, 0, sizeof(ans));
  n = int(str.length());
  // init
  P[0] = 1;
  lhash[0] = str[0];
  rhash[0] = str[n - 1];
  for (int i = 1, j = n - 2; i < n; ++i, --j){
    lhash[i] = lhash[i - 1] * MAGIC + str[i];
    rhash[n - 1 - j] = rhash[n - j - 2] * MAGIC + str[j];
  }
  for (int i = 1; i < N; ++i) {
    P[i] = P[i - 1] * MAGIC;
  }
  for (int i = 0; i < n; ++i) {
    ans[1] += 1;
    for (int j = i + 1; j < n; ++j) {
      int idx = check(i, j);
      //if (idx) {
      //  printf("idx:%d\n", idx);
      //  std::cout << str.substr(i, j - i + 1) << std::endl;
      //}
      for (int k = 1; k <= idx; ++k) {
        ++ans[k];
      }
    }
  }
  for (int i = 1; i <= n; ++i) {
    printf("%d%c", ans[i], i == n ? '\n' : ' ');
  }
  return 0;
}


/*************************************************************************
    > File Name: d.cpp
    > Author:zhoubo_NLP
    > Mail: zhouboacmer@qq.com
    > Created Time: 日  8/13 20:34:03 2017
    > Usage:
 ************************************************************************/

#include<iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>

std::string str;
const int MAGIC = 48533;
const int N = 5001;
int ans[N];
int lhash[N];
int rhash[N];
int P[N];
int n;

int get_lhash(int l, int r) {
  int len = r - l + 1;
  if (l == 0) {
    return lhash[r];
  } else {
    return lhash[r] - lhash[l - 1] * P[len];
  }
}

int get_rhash(int l, int r) {
  int len = r - l + 1;
  l = n - 1 - l;
  r = n - 1 - r;
  std::swap(l, r);
  if (l == 0) {
    return rhash[r];
  } else {
    return rhash[r] - rhash[l - 1] * P[len];
  }
}

int check(int l, int r) {
  if (l == r) {
    return 1;
  }
  int len = r - l + 1;
  int m = len >> 1;
  int l_hash_val = get_lhash(l, l + m - 1);
  int r_hash_val = get_rhash(r - m + 1, r);
  if (l_hash_val != r_hash_val) {
    return 0;
  } else {
    return check(l, l + m - 1) + 1;
  }
}

int main() {
  std::cin >> str;
  memset(ans, 0, sizeof(ans));
  n = int(str.length());
  // init
  P[0] = 1;
  lhash[0] = str[0];
  rhash[0] = str[n - 1];
  for (int i = 1, j = n - 2; i < n; ++i, --j){
    lhash[i] = lhash[i - 1] * MAGIC + str[i];
    rhash[n - 1 - j] = rhash[n - j - 2] * MAGIC + str[j];
  }
  for (int i = 1; i < N; ++i) {
    P[i] = P[i - 1] * MAGIC;
  }
  for (int i = 0; i < n; ++i) {
    ans[1] += 1;
    for (int j = i + 1; j < n; ++j) {
      int idx = check(i, j);
      //if (idx) {
      //  printf("idx:%d\n", idx);
      //  std::cout << str.substr(i, j - i + 1) << std::endl;
      //}
      for (int k = 1; k <= idx; ++k) {
        ++ans[k];
      }
    }
  }
  for (int i = 1; i <= n; ++i) {
    printf("%d%c", ans[i], i == n ? '\n' : ' ');
  }
  return 0;
}


/*************************************************************************
    > File Name: d.cpp
    > Author:zhoubo_NLP
    > Mail: zhouboacmer@qq.com
    > Created Time: 日  8/13 20:34:03 2017
    > Usage:
 ************************************************************************/

#include<iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>

std::string str;
const int MAGIC = 48533;
const int N = 5001;
int ans[N];
int lhash[N];
int rhash[N];
int P[N];
int n;

int get_lhash(int l, int r) {
  int len = r - l + 1;
  if (l == 0) {
    return lhash[r];
  } else {
    return lhash[r] - lhash[l - 1] * P[len];
  }
}

int get_rhash(int l, int r) {
  int len = r - l + 1;
  l = n - 1 - l;
  r = n - 1 - r;
  std::swap(l, r);
  if (l == 0) {
    return rhash[r];
  } else {
    return rhash[r] - rhash[l - 1] * P[len];
  }
}

int check(int l, int r) {
  if (l == r) {
    return 1;
  }
  int len = r - l + 1;
  int m = len >> 1;
  int l_hash_val = get_lhash(l, l + m - 1);
  int r_hash_val = get_rhash(r - m + 1, r);
  if (l_hash_val != r_hash_val) {
    return 0;
  } else {
    return check(l, l + m - 1) + 1;
  }
}

int main() {
  std::cin >> str;
  memset(ans, 0, sizeof(ans));
  n = int(str.length());
  // init
  P[0] = 1;
  lhash[0] = str[0];
  rhash[0] = str[n - 1];
  for (int i = 1, j = n - 2; i < n; ++i, --j){
    lhash[i] = lhash[i - 1] * MAGIC + str[i];
    rhash[n - 1 - j] = rhash[n - j - 2] * MAGIC + str[j];
  }
  for (int i = 1; i < N; ++i) {
    P[i] = P[i - 1] * MAGIC;
  }
  for (int i = 0; i < n; ++i) {
    ans[1] += 1;
    for (int j = i + 1; j < n; ++j) {
      int idx = check(i, j);
      //if (idx) {
      //  printf("idx:%d\n", idx);
      //  std::cout << str.substr(i, j - i + 1) << std::endl;
      //}
      for (int k = 1; k <= idx; ++k) {
        ++ans[k];
      }
    }
  }
  for (int i = 1; i <= n; ++i) {
    printf("%d%c", ans[i], i == n ? '\n' : ' ');
  }
  return 0;
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
#define maxn 5005
char s[maxn];int n;
ll p1=1000000007,p2=99879471;
ll h1[maxn],h2[maxn];
ll b1[maxn],b2[maxn];

inline ll hash1(int l,int r)
{
	return (h1[r]+p2-h1[l-1]*b1[r-l+1]%p2)%p2;
}

inline ll hash2(int l,int r)
{
	return (h2[r]+p1-h2[l-1]*b2[r-l+1]%p1)%p1;
}

inline int same(int l1,int r1,int l2,int r2)
{
	return hash1(l1,r1)==hash1(l2,r2)&&hash2(l1,r1)==hash2(l2,r2);
}

void init()
{
	gets(s+1);n=strlen(s+1);
	b1[0]=b2[0]=1;
	for(int i=1;i<=n;++i)
	{
		h1[i]=(h1[i-1]*p1+s[i]-'a')%p2;
		h2[i]=(h2[i-1]*p2+s[i]-'a')%p1;
		b1[i]=b1[i-1]*p1%p2;
		b2[i]=b2[i-1]*p2%p1;
	}
}

int f[maxn][maxn];
ll ans[maxn];

void solve()
{
	for(int i=1;i<=n;++i)
	{
		f[i][1]=1;
		for(int j=1;j<i&&i+j<=n;++j)
		{
			if(s[i-j]!=s[i+j])break;
			f[i-j][j<<1|1]=1;
		}
	}

	for(int i=1;i<n;++i)
	{
		for(int j=0;j<i&&i+j+1<=n;++j)
		{
			if(s[i-j]!=s[i+j+1])break;
			f[i-j][(j+1)<<1]=1;
		}
	}

	for(int j=2;j<=n;++j)
	{
		int t=j>>1;
		for(int i=1;i+j-1<=n;++i)
			if(same(i,i+t-1,i+j-t,i+j-1))
				f[i][j]=max(f[i][j],f[i][t]+1);
	}

	for(int i=1;i<=n;++i)
		for(int j=1;i+j-1<=n;++j)
			++ans[f[i][j]];
	for(int i=n;i>1;--i)
		ans[i-1]+=ans[i];
	for(int i=1;i<n;++i)
		printf("%I64d ",ans[i]);
	printf("%I64d\n",ans[n]);
}

int main()
{
	init();
	solve();
	return 0;
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
#define maxn 5005
char s[maxn];int n;
ll p1=839189117,p2=998794713;
ll h1[maxn],h2[maxn];
ll b1[maxn],b2[maxn];

inline ll hash1(int l,int r)
{
	return (h1[r]+p2-h1[l-1]*b1[r-l+1]%p2)%p2;
}

inline ll hash2(int l,int r)
{
	return (h2[r]+p1-h2[l-1]*b2[r-l+1]%p1)%p1;
}

inline int same(int l1,int r1,int l2,int r2)
{
	return hash1(l1,r1)==hash1(l2,r2)&&hash2(l1,r1)==hash2(l2,r2);
}

void init()
{
	gets(s+1);n=strlen(s+1);
	b1[0]=b2[0]=1;
	for(int i=1;i<=n;++i)
	{
		h1[i]=(h1[i-1]*p1+s[i]-'a')%p2;
		h2[i]=(h2[i-1]*p2+s[i]-'a')%p1;
		b1[i]=b1[i-1]*p1%p2;
		b2[i]=b2[i-1]*p2%p1;
	}
}

int f[maxn][maxn];
ll ans[maxn];

void solve()
{
	for(int i=1;i<=n;++i)
	{
		f[i][1]=1;
		for(int j=1;j<i&&i+j<=n;++j)
		{
			if(s[i-j]!=s[i+j])break;
			f[i-j][j<<1|1]=1;
		}
	}

	for(int i=1;i<n;++i)
	{
		for(int j=0;j<i&&i+j+1<=n;++j)
		{
			if(s[i-j]!=s[i+j+1])break;
			f[i-j][(j+1)<<1]=1;
		}
	}

	for(int j=2;j<=n;++j)
	{
		int t=j>>1;
		for(int i=1;i+j-1<=n;++i)
			if(same(i,i+t-1,i+j-t,i+j-1))
				f[i][j]=max(f[i][j],f[i][t]+1);
	}

	for(int i=1;i<=n;++i)
		for(int j=1;i+j-1<=n;++j)
			++ans[f[i][j]];
	for(int i=n;i>1;--i)
		ans[i-1]+=ans[i];
	for(int i=1;i<n;++i)
		printf("%I64d ",ans[i]);
	printf("%I64d\n",ans[n]);
}

int main()
{
	init();
	solve();
	return 0;
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
#define maxn 5005
char s[maxn];int n;
ll p1=1000000007,p2=99879471;
ll h1[maxn],h2[maxn];
ll b1[maxn],b2[maxn];

inline ll hash1(int l,int r)
{
	return (h1[r]+p2-h1[l-1]*b1[r-l+1]%p2)%p2;
}

inline ll hash2(int l,int r)
{
	return (h2[r]+p1-h2[l-1]*b2[r-l+1]%p1)%p1;
}

inline int same(int l1,int r1,int l2,int r2)
{
	return hash1(l1,r1)==hash1(l2,r2)&&hash2(l1,r1)==hash2(l2,r2);
}

void init()
{
	gets(s+1);n=strlen(s+1);
	b1[0]=b2[0]=1;
	for(int i=1;i<=n;++i)
	{
		h1[i]=(h1[i-1]*p1+s[i]-'a')%p2;
		h2[i]=(h2[i-1]*p2+s[i]-'a')%p1;
		b1[i]=b1[i-1]*p1%p2;
		b2[i]=b2[i-1]*p2%p1;
	}
}

int f[maxn][maxn],g[maxn][maxn],ans[maxn];

void solve()
{
	for(int i=1;i<=n;++i)
	{
		f[i][1]=1;
		for(int j=1;j<i&&i+j<=n;++j)
		{
			if(s[i-j]!=s[i+j])break;
			f[i-j][j<<1|1]=1;
		}
	}

	for(int i=1;i<n;++i)
	{
		for(int j=0;j<i&&i+j+1<=n;++j)
		{
			if(s[i-j]!=s[i+j+1])break;
			f[i-j][(j+1)<<1]=1;
		}
	}

	for(int j=2;j<=n;++j)
	{
		int t=j>>1;
		for(int i=1;i+j-1<=n;++i)
			if(same(i,i+t-1,i+j-t,i+j-1))
				f[i][j]=max(f[i][j],f[i][t]+1);
	}

	for(int i=1;i<=n;++i)
		for(int j=1;i+j-1<=n;++j)
			++ans[f[i][j]];
	for(int i=n;i>1;--i)
		ans[i-1]+=ans[i];
	for(int i=1;i<n;++i)
		printf("%d ",ans[i]);
	printf("%d\n",ans[n]);
}

int main()
{
	init();
	solve();
	return 0;
}


#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;
long long tmp=10;
long long Tmp=1;
long long hash1[5005],hash2[5005];
string s;
int len;
int a[5005];
int ans[10005];
int dp[5005][5005];
long long ksm(long long x,int y){
	if (y==0){
		return 1ll;
	}
	if (y==1){
		return x;
	}
	if (y%2==0){
		return ksm(x*x,y/2);
	}
	else{
		return x*ksm(x*x,y/2);
	}
}
long long gethash1(int l,int r){
	long long re=hash1[r]-hash1[l-1]*ksm(tmp,r-l+1);//ksm(tmp,l-1);
	if (s[0]=='d')cout<<re<<" ";
	return re;
}
long long gethash2(int l,int r){
	long long re=(hash2[r]-hash2[l-1])/ksm(tmp,l-1);
	if (s[0]=='d')cout<<re<<" ";
	return re;
}
int main(){
	cin>>s;
	len=s.size();
	if (s[0]=='d')cout<<"len="<<len<<endl;
	for (int i=1;i<=len;i++){
		a[i]=s[i-1]-'a'+1;
	}
	if (s[0]=='d')cout<<"?"<<endl;
	for (int i=1;i<=len;i++){
		hash1[i]=hash1[i-1]*tmp+(long long)a[i];
	}
	for (int i=1;i<=len;i++){
		hash2[i]=hash2[i-1]+(long long)a[i]*Tmp;
		Tmp*=tmp;
	}
	if (s[0]=='d')cout<<"?"<<endl;
	/*for (int i=1;i<=len;i++){
		cout<<hash1[i]<<" ";
	}
	cout<<endl;
	for (int i=1;i<=len;i++){
		cout<<hash2[i]<<" ";
	}
	cout<<endl;*/
	//cout<<ksm(2,10);
	for (int L=1;L<=len;L++){
		for (int i=1;i<=len;i++){
			if (i+L-1>len){
				break;
			}
			//cout<<i<<" "<<i+L/2-1<<" "<<i+L-1-L/2+1<<" "<<i+L-1<<endl;
			int x1=i;
			int x2=i+L/2;
			if (L%2==0){
				x2--;
			}
			int y1=i+L-1-L/2;
			if (L%2==0){
				y1++;
			}
			int y2=i+L-1;
			if (L!=1 && x2==y1){
				x2--;
				y1++;
			}
			if (s[0]=='d')cout<<x1<<" "<<x2<<" "<<y1<<" "<<y2<<endl;
			//cout<<gethash1(x1,x2)<<" "<<gethash2(y1,y2)<<endl;
			if (gethash1(x1,x2)==gethash2(y1,y2)){
				dp[i][i+L-1]=dp[i][x2]+1;
				//cout<<dp[i][i+L-1]<<endl;
				ans[dp[i][i+L-1]]++;
			}
		}
	}
	vector<int> Out;
	int Ans=0;
	for (int i=len;i>=1;i--){
		Ans+=ans[i];
		//cout<<Ans<<" ";
		Out.push_back(Ans);
	}
	for (int i=Out.size()-1;i>=0;i--){
		cout<<Out[i]<<" ";
	}
	return 0;
}


#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
using namespace std;
const long long tmp=1e9+7;
string s;
int a[5005];
long long hash1[5005];
long long hash2[5005];
int k[5005][5005];
int ans[5005];
int len;
long long Pow[5005];
bool palin(int x,int y){
	long long Hash1=hash1[y]-hash1[x-1]*Pow[y-x+1];
	long long Hash2=hash2[x]-hash2[y+1]*Pow[y-x+1];
	if (Hash1==Hash2){
		return true;
	}
	else{
		return false;
	}
}
void getans(int x,int y){
	if (k[x][y]!=-1){
		return;
	}
	if (!palin(x,y)){
		k[x][y]=0;
		return;
	}
	int len=(y-x+1)/2;
	if (len==0){
		k[x][y]=1;
		return;
	}
	getans(x,x+len-1);
	k[x][y]=1+k[x][x+len-1];
	return;
}
int main(){
	memset(k,-1,sizeof(k));
	cin>>s;
	len=s.size();
	if (s[0]=='d')cout<<"len="<<len<<endl;
	for (int i=0;i<len;i++){
		a[i+1]=s[i]-'a'+1;
	}
	if (s[0]=='d')cout<<"?"<<endl;
	for (int i=1;i<=len;i++){
		hash1[i]=hash1[i-1]*tmp+a[i];
	}
	for (int i=len;i>=1;i--){
		hash2[i]=hash2[i+1]*tmp+a[i];
	}
	Pow[0]=1;
	for (int i=1;i<=len+5;i++){
		Pow[i]=Pow[i-1]*tmp;
	}
	if (s[0]=='d')cout<<"?";
	for (int i=1;i<=len;i++){
		for (int j=i;j<=len;j++){
			getans(i,j);
			ans[k[i][j]]++;
		}
	}
	vector<int> Out;
	int Ans=0;
	for (int i=len;i>=1;i--){
		Ans+=ans[i];
		//cout<<Ans<<" ";
		Out.push_back(Ans);
	}
	for (int i=Out.size()-1;i>=0;i--){
		cout<<Out[i]<<" ";
	}
	return 0;
}


#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;
long long tmp=10;
long long Tmp=1;
long long hash1[5005],hash2[5005];
string s;
int len;
int a[5005];
int ans[10005];
int dp[5005][5005];
long long ksm(long long x,int y){
	if (y==0){
		return 1ll;
	}
	if (y==1){
		return x;
	}
	if (y%2==0){
		return ksm(x*x,y/2);
	}
	else{
		return x*ksm(x*x,y/2);
	}
}
long long gethash1(int l,int r){
	long long re=hash1[r]-hash1[l-1]*ksm(tmp,r-l+1);//ksm(tmp,l-1);
	//if (s[0]=='d')cout<<re<<" ";
	return re;
}
long long gethash2(int l,int r){
	long long re=(hash2[r]-hash2[l-1])/ksm(tmp,l-1);
	//if (s[0]=='d')cout<<re<<" ";
	return re;
}
int main(){
	cin>>s;
	len=s.size();
	//if (s[0]=='d')cout<<"len="<<len<<endl;
	for (int i=1;i<=len;i++){
		a[i]=s[i-1]-'a'+1;
	}
	//if (s[0]=='d')cout<<"?"<<endl;
	for (int i=1;i<=len;i++){
		hash1[i]=hash1[i-1]*tmp+(long long)a[i];
	}
	for (int i=1;i<=len;i++){
		hash2[i]=hash2[i-1]+(long long)a[i]*Tmp;
		Tmp*=tmp;
	}
	//if (s[0]=='d')cout<<"?"<<endl;
	/*for (int i=1;i<=len;i++){
		cout<<hash1[i]<<" ";
	}
	cout<<endl;
	for (int i=1;i<=len;i++){
		cout<<hash2[i]<<" ";
	}
	cout<<endl;*/
	//cout<<ksm(2,10);
	for (int L=1;L<=len;L++){
		for (int i=1;i<=len;i++){
			if (i+L-1>len){
				break;
			}
			//cout<<i<<" "<<i+L/2-1<<" "<<i+L-1-L/2+1<<" "<<i+L-1<<endl;
			int x1=i;
			int x2=i+L/2;
			if (L%2==0){
				x2--;
			}
			int y1=i+L-1-L/2;
			if (L%2==0){
				y1++;
			}
			int y2=i+L-1;
			if (L!=1 && x2==y1){
				x2--;
				y1++;
			}
			if (s[0]=='d')cout<<x1<<" "<<x2<<" "<<y1<<" "<<y2<<" ";
			if (s[0]=='d')cout<<gethash1(x1,x2)<<" "<<gethash2(y1,y2)<<endl;
			if (gethash1(x1,x2)==gethash2(y1,y2)){
				dp[i][i+L-1]=dp[i][x2]+1;
				//cout<<dp[i][i+L-1]<<endl;
				ans[dp[i][i+L-1]]++;
			}
		}
	}
	vector<int> Out;
	int Ans=0;
	for (int i=len;i>=1;i--){
		Ans+=ans[i];
		//cout<<Ans<<" ";
		Out.push_back(Ans);
	}
	for (int i=Out.size()-1;i>=0;i--){
		cout<<Out[i]<<" ";
	}
	return 0;
}


#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;
long long tmp=10;
long long Tmp=1;
long long hash1[5005],hash2[5005];
string s;
int len;
int a[5005];
int ans[10005];
int dp[5005][5005];
long long ksm(long long x,int y){
	if (y==0){
		return 1ll;
	}
	if (y==1){
		return x;
	}
	if (y%2==0){
		return ksm(x*x,y/2);
	}
	else{
		return x*ksm(x*x,y/2);
	}
}
long long gethash1(int l,int r){
	long long re=hash1[r]-hash1[l-1]*ksm(tmp,r-l+1);//ksm(tmp,l-1);
	if (s[0]=='d')cout<<re<<" ";
	return re;
}
long long gethash2(int l,int r){
	long long re=(hash2[r]-hash2[l-1])/ksm(tmp,l-1);
	if (s[0]=='d')cout<<re<<" ";
	return re;
}
int main(){
	cin>>s;
	len=s.size();
	for (int i=1;i<=len;i++){
		a[i]=s[i-1]-'a'+1;
	}
	for (int i=1;i<=len;i++){
		hash1[i]=hash1[i-1]*tmp+(long long)a[i];
	}
	for (int i=1;i<=len;i++){
		hash2[i]=hash2[i-1]+(long long)a[i]*Tmp;
		Tmp*=tmp;
	}
	/*for (int i=1;i<=len;i++){
		cout<<hash1[i]<<" ";
	}
	cout<<endl;
	for (int i=1;i<=len;i++){
		cout<<hash2[i]<<" ";
	}
	cout<<endl;*/
	//cout<<ksm(2,10);
	for (int L=1;L<=len;L++){
		for (int i=1;i<=len;i++){
			if (i+L-1>len){
				break;
			}
			//cout<<i<<" "<<i+L/2-1<<" "<<i+L-1-L/2+1<<" "<<i+L-1<<endl;
			int x1=i;
			int x2=i+L/2;
			if (L%2==0){
				x2--;
			}
			int y1=i+L-1-L/2;
			if (L%2==0){
				y1++;
			}
			int y2=i+L-1;
			if (L!=1 && x2==y1){
				x2--;
				y1++;
			}
			//cout<<x1<<" "<<x2<<" "<<y1<<" "<<y2<<endl;
			//cout<<gethash1(x1,x2)<<" "<<gethash2(y1,y2)<<endl;
			if (gethash1(x1,x2)==gethash2(y1,y2)){
				dp[i][i+L-1]=dp[i][x2]+1;
				//cout<<dp[i][i+L-1]<<endl;
				ans[dp[i][i+L-1]]++;
			}
		}
	}
	vector<int> Out;
	int Ans=0;
	for (int i=len;i>=1;i--){
		Ans+=ans[i];
		//cout<<Ans<<" ";
		Out.push_back(Ans);
	}
	for (int i=Out.size()-1;i>=0;i--){
		cout<<Out[i]<<" ";
	}
	return 0;
}


#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;
long long tmp=10;
long long Tmp=1;
long long hash1[5005],hash2[5005];
string s;
int len;
int a[5005];
int ans[5005];
int dp[5005][5005];
long long ksm(long long x,int y){
	if (y==0){
		return 1ll;
	}
	if (y==1){
		return x;
	}
	if (y%2==0){
		return ksm(x*x,y/2);
	}
	else{
		return x*ksm(x*x,y/2);
	}
}
long long gethash1(int l,int r){
	long long re=hash1[r]-hash1[l-1]*ksm(tmp,r-l+1);//ksm(tmp,l-1);
	return re;
}
long long gethash2(int l,int r){
	long long re=(hash2[r]-hash2[l-1])/ksm(tmp,l-1);
	return re;
}
int main(){
	cin>>s;
	len=s.size();
	for (int i=1;i<=len;i++){
		a[i]=s[i-1]-'a'+1;
	}
	for (int i=1;i<=len;i++){
		hash1[i]=hash1[i-1]*tmp+(long long)a[i];
	}
	for (int i=1;i<=len;i++){
		hash2[i]=hash2[i-1]+(long long)a[i]*Tmp;
		Tmp*=tmp;
	}
	/*for (int i=1;i<=len;i++){
		cout<<hash1[i]<<" ";
	}
	cout<<endl;
	for (int i=1;i<=len;i++){
		cout<<hash2[i]<<" ";
	}
	cout<<endl;*/
	//cout<<ksm(2,10);
	for (int L=1;L<=len;L++){
		for (int i=1;i<=len;i++){
			if (i+L-1>len){
				break;
			}
			//cout<<i<<" "<<i+L/2-1<<" "<<i+L-1-L/2+1<<" "<<i+L-1<<endl;
			int x1=i;
			int x2=i+L/2;
			if (L%2==0){
				x2--;
			}
			int y1=i+L-1-L/2;
			if (L%2==0){
				y1++;
			}
			int y2=i+L-1;
			if (L!=1 && x2==y1){
				x2--;
				y1++;
			}
			//cout<<x1<<" "<<x2<<" "<<y1<<" "<<y2<<endl;
			//cout<<gethash1(x1,x2)<<" "<<gethash2(y1,y2)<<endl;
			if (gethash1(x1,x2)==gethash2(y1,y2)){
				dp[i][i+L-1]=dp[i][x2]+1;
				//cout<<dp[i][i+L-1]<<endl;
				ans[dp[i][i+L-1]]++;
			}
		}
	}
	vector<int> Out;
	int Ans=0;
	for (int i=len;i>=1;i--){
		Ans+=ans[i];
		//cout<<Ans<<" ";
		Out.push_back(Ans);
	}
	for (int i=Out.size()-1;i>=0;i--){
		cout<<Out[i]<<" ";
	}
	return 0;
}


#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;
long long tmp=233;
long long Tmp=1;
long long hash1[5005],hash2[5005];
string s;
int len;
int a[5005];
int ans[5005];
int dp[5005][5005];
long long ksm(long long x,int y){
	if (y==0){
		return 1ll;
	}
	if (y==1){
		return x;
	}
	if (y%2==0){
		return ksm(x*x,y/2);
	}
	else{
		return x*ksm(x*x,y/2);
	}
}
long long gethash1(int l,int r){
	long long re=hash1[r]-hash1[l-1]*ksm(tmp,r-l+1);//ksm(tmp,l-1);
	return re;
}
long long gethash2(int l,int r){
	long long re=(hash2[r]-hash2[l-1])/ksm(tmp,l-1);
	return re;
}
int main(){
	cin>>s;
	len=s.size();
	for (int i=1;i<=len;i++){
		a[i]=s[i-1]-'a'+1;
	}
	for (int i=1;i<=len;i++){
		hash1[i]=hash1[i-1]*tmp+(long long)a[i];
	}
	for (int i=1;i<=len;i++){
		hash2[i]=hash2[i-1]+(long long)a[i]*Tmp;
		Tmp*=tmp;
	}
	/*for (int i=1;i<=len;i++){
		cout<<hash1[i]<<" ";
	}
	cout<<endl;
	for (int i=1;i<=len;i++){
		cout<<hash2[i]<<" ";
	}
	cout<<endl;*/
	//cout<<ksm(2,10);
	for (int L=1;L<=len;L++){
		for (int i=1;i<=len;i++){
			if (i+L-1>len){
				break;
			}
			//cout<<i<<" "<<i+L/2-1<<" "<<i+L-1-L/2+1<<" "<<i+L-1<<endl;
			int x1=i;
			int x2=i+L/2;
			if (L%2==0){
				x2--;
			}
			int y1=i+L-1-L/2;
			if (L%2==0){
				y1++;
			}
			int y2=i+L-1;
			if (L!=1 && x2==y1){
				x2--;
				y1++;
			}
			//cout<<x1<<" "<<x2<<" "<<y1<<" "<<y2<<endl;
			//cout<<gethash1(x1,x2)<<" "<<gethash2(y1,y2)<<endl;
			if (gethash1(x1,x2)==gethash2(y1,y2)){
				dp[i][i+L-1]=dp[i][x2]+1;
				//cout<<dp[i][i+L-1]<<endl;
				ans[dp[i][i+L-1]]++;
			}
		}
	}
	vector<int> Out;
	int Ans=0;
	for (int i=len;i>=1;i--){
		Ans+=ans[i];
		//cout<<Ans<<" ";
		Out.push_back(Ans);
	}
	for (int i=Out.size()-1;i>=0;i--){
		cout<<Out[i]<<" ";
	}
	return 0;
}


#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;
long long tmp=27;
long long Tmp=1;
long long hash1[5005],hash2[5005];
string s;
int len;
int a[5005];
int ans[5005];
int dp[5005][5005];
long long ksm(long long x,int y){
	if (y==0){
		return 1ll;
	}
	if (y==1){
		return x;
	}
	if (y%2==0){
		return ksm(x*x,y/2);
	}
	else{
		return x*ksm(x*x,y/2);
	}
}
long long gethash1(int l,int r){
	long long re=hash1[r]-hash1[l-1]*ksm(tmp,r-l+1);//ksm(tmp,l-1);
	return re;
}
long long gethash2(int l,int r){
	long long re=(hash2[r]-hash2[l-1])/ksm(tmp,l-1);
	return re;
}
int main(){
	cin>>s;
	len=s.size();
	for (int i=1;i<=len;i++){
		a[i]=s[i-1]-'a'+1;
	}
	for (int i=1;i<=len;i++){
		hash1[i]=hash1[i-1]*tmp+a[i];
	}
	for (int i=1;i<=len;i++){
		hash2[i]=hash2[i-1]+a[i]*Tmp;
		Tmp*=tmp;
	}
	/*for (int i=1;i<=len;i++){
		cout<<hash1[i]<<" ";
	}
	cout<<endl;
	for (int i=1;i<=len;i++){
		cout<<hash2[i]<<" ";
	}
	cout<<endl;*/
	//cout<<ksm(2,10);
	for (int L=1;L<=len;L++){
		for (int i=1;i<=len;i++){
			if (i+L-1>len){
				break;
			}
			//cout<<i<<" "<<i+L/2-1<<" "<<i+L-1-L/2+1<<" "<<i+L-1<<endl;
			int x1=i;
			int x2=i+L/2;
			if (L%2==0){
				x2--;
			}
			int y1=i+L-1-L/2;
			if (L%2==0){
				y1++;
			}
			int y2=i+L-1;
			if (L!=1 && x2==y1){
				x2--;
				y1++;
			}
			//cout<<x1<<" "<<x2<<" "<<y1<<" "<<y2<<endl;
			//cout<<gethash1(x1,x2)<<" "<<gethash2(y1,y2)<<endl;
			if (gethash1(x1,x2)==gethash2(y1,y2)){
				dp[i][i+L-1]=dp[i][x2]+1;
				//cout<<dp[i][i+L-1]<<endl;
				ans[dp[i][i+L-1]]++;
			}
		}
	}
	vector<int> Out;
	int Ans=0;
	for (int i=len;i>=1;i--){
		Ans+=ans[i];
		//cout<<Ans<<" ";
		Out.push_back(Ans);
	}
	for (int i=Out.size()-1;i>=0;i--){
		cout<<Out[i]<<" ";
	}
	return 0;
}


#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;
const long long tmp=1e9+7;
string s;
int a[5005];
long long hash1[5005];
long long hash2[5005];
int k[5005][5005];
int ans[5005];
int len;
long long Pow[5005];
bool palin(int x,int y){
	long long Hash1=hash1[y]-hash1[x-1]*Pow[y-x+1];
	long long Hash2=hash2[x]-hash2[y+1]*Pow[y-x+1];
	if (Hash1==Hash2){
		return true;
	}
	else{
		return false;
	}
}
void getans(int x,int y){
	if (k[x][y]!=-1){
		return;
	}
	if (!palin(x,y)){
		k[x][y]=0;
		return;
	}
	int len=(y-x+1)/2;
	if (len==0){
		k[x][y]=1;
		return;
	}
	k[x][y]=1+k[x][x+len-1];
	return;
}
int main(){
	memset(k,-1,sizeof(k));
	cin>>s;
	len=s.size();
	for (int i=0;i<len;i++){
		a[i+1]=s[i]-'a'+1;
	}
	for (int i=1;i<=len;i++){
		hash1[i]=hash1[i-1]*tmp+a[i];
	}
	for (int i=len;i>=1;i--){
		hash2[i]=hash2[i+1]*tmp+a[i];
	}
	Pow[0]=1;
	for (int i=1;i<=len+5;i++){
		Pow[i]=Pow[i-1]*tmp;
	}
	for (int i=1;i<=len;i++){
		for (int j=i;j<=len;j++){
			getans(i,j);
			ans[k[i][j]]++;
		}
	}
	vector<int> Out;
	int Ans=0;
	for (int i=len;i>=1;i--){
		Ans+=ans[i];
		//cout<<Ans<<" ";
		Out.push_back(Ans);
	}
	for (int i=Out.size()-1;i>=0;i--){
		cout<<Out[i]<<" ";
	}
	return 0;
}


#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
using namespace std;
const long long tmp=1e9+7;
string s;
int a[5005];
long long hash1[5005];
long long hash2[5005];
int k[5005][5005];
int ans[5005];
int len;
long long Pow[5005];
bool palin(int x,int y){
	long long Hash1=hash1[y]-hash1[x-1]*Pow[y-x+1];
	long long Hash2=hash2[x]-hash2[y+1]*Pow[y-x+1];
	if (Hash1==Hash2){
		return true;
	}
	else{
		return false;
	}
}
void getans(int x,int y){
	if (k[x][y]!=-1){
		return;
	}
	if (!palin(x,y)){
		k[x][y]=0;
		return;
	}
	int len=(y-x+1)/2;
	if (len==0){
		k[x][y]=1;
		return;
	}
	getans(x,x+len-1);
	k[x][y]=1+k[x][x+len-1];
	return;
}
int main(){
	memset(k,-1,sizeof(k));
	cin>>s;
	len=s.size();
	if (s[0]=='d')cout<<"len="<<len<<endl;
	for (int i=0;i<len;i++){
		a[i+1]=s[i]-'a'+1;
	}
	if (s[0]=='d')cout<<"??"<<endl;
	for (int i=1;i<=len;i++){
		hash1[i]=hash1[i-1]*tmp+a[i];
	}
	for (int i=len;i>=1;i--){
		hash2[i]=hash2[i+1]*tmp+a[i];
	}
	Pow[0]=1;
	for (int i=1;i<=len+5;i++){
		Pow[i]=Pow[i-1]*tmp;
	}
	if (s[0]=='d')cout<<"?";
	for (int i=1;i<=len;i++){
		for (int j=i;j<=len;j++){
			getans(i,j);
			ans[k[i][j]]++;
		}
	}
	vector<int> Out;
	int Ans=0;
	for (int i=len;i>=1;i--){
		Ans+=ans[i];
		//cout<<Ans<<" ";
		Out.push_back(Ans);
	}
	for (int i=Out.size()-1;i>=0;i--){
		cout<<Out[i]<<" ";
	}
	return 0;
}