import std.algorithm;
import std.conv;
import std.range;
import std.stdio;
import std.string;
import std.typecons;

void main()
{
	stdin.byLineCopy.parse.expand.solve.writeln;
}

auto parse( Range )( Range input )
if( isInputRange!Range && is( ElementType!Range == string ) )
{
	auto nm = input.front.split.to!( long[] );
	return tuple( nm[ 0 ], nm[ 1 ] );
}

auto solve( long n, long m )
{
	// 3 * 3 までのパターンは普通にシミュレートする
	auto h = ( 3 < n ) ? 3 : n;
	auto w = ( 3 < m ) ? 3 : m;
	auto table = new bool[][]( h, w );
	foreach( y; 0 .. h )
	{
		foreach( x; 0 .. w )
		{
			table[ y ][ x ] = !table[ y ][ x ];
			if( 0 < x     ) table[ y ][ x - 1 ] = !table[ y ][ x - 1 ];
			if( x < w - 1 ) table[ y ][ x + 1 ] = !table[ y ][ x + 1 ];
			
			if( 0 < y )
			{
				table[ y - 1 ][ x ] = !table[ y - 1 ][ x ];
				if( 0 < x     ) table[ y - 1 ][ x - 1 ] = !table[ y - 1 ][ x - 1 ];
				if( x < w - 1 ) table[ y - 1 ][ x + 1 ] = !table[ y - 1 ][ x + 1 ];
			}
			
			if( y < h - 1 )
			{
				table[ y + 1 ][ x ] = !table[ y + 1 ][ x ];
				if( 0 < x     ) table[ y + 1 ][ x - 1 ] = !table[ y + 1 ][ x - 1 ];
				if( x < w - 1 ) table[ y + 1 ][ x + 1 ] = !table[ y + 1 ][ x + 1 ];
			}
		}
	}
	
	// 表の合計
	auto c = table.joiner.count( true );
	
	// 3 * 3 より大きいパターンは真ん中が広がるだけだから計算で出す
	if( 3 <= n && 3 <= m )
	{
		if( table[ 1 ][ 1 ] ) c += ( n - 2 ) * ( m - 2 ) - 1;		// 真ん中を二重計上しないように注意
	}
	
	// 片方だけ3以上のパターンその1
	if( 3 <= n && m < 3 )
	{
		if( table[ 1 ][ 0 ] ) c += ( n - 2 ) * m - 1;
	}
	
	// 片方だけ3以上のパターンその1
	if( n < 3 && 3 <= m )
	{
		if( table[ 0 ][ 1 ] ) c += n * ( m - 2 ) - 1;
	}
	
	return c;
}
