unittest
{
	assert( [ "2", "2 2", "9 1" ].parse.expand.solve == 3 );
	assert( [ "3", "1 1", "0 8", "7 1" ].parse.expand.solve == 9 );
	
	assert( [ "2", "4 6", "9 1" ].parse.expand.solve == 9 );		// 追加ケース
	assert( [ "2", "4 7", "9 1" ].parse.expand.solve == 11 );		// 追加ケース
	assert( [ "2", "4 8", "9 1" ].parse.expand.solve == 12 );		// 追加ケース
	assert( [ "200000" ].chain( "9 5000000000".repeat( 200000 ) ).parse.expand.solve == 1999999999999998 );		// 追加ケース
}



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

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

auto parse( Range )( Range input )
if( isInputRange!Range && is( ElementType!Range == string ) )
{
	auto m = input.front.to!( long );
	auto dcs = new long[ 2 ][ m ];
	foreach( ref dc; dcs )
	{
		input.popFront;
		dc = input.front.split.to!( long[] );
	}
	return tuple( dcs );
}

auto solve( long[ 2 ][] dcs )
{
	auto ans = 0L;
	long[] ds;
	foreach( dc; dcs )
	{
		// 同じdの桁を足し算
		auto r = solve2( dc[ 0 ], dc[ 1 ] );
		ds ~= r[ 0 ];
		ans += r[ 1 ];
		
		// 違うdの桁を足し算
		while( 2 <= ds.length )
		{
			auto dt = ds[ 0 ] + ds[ 1 ];
			ds.popFront;
			
			if( dt < 10 )
			{
				ds.front = dt;
				ans++;
			}
			else
			{
				ds.front = dt % 10 + 1;
				ans += 2;
			}
		}
	}
	return ans;
}

Tuple!( long[], long ) solve2( long d, long c )
{
	long[] ds;
	auto t = 0L;
	
	// 10 <= d * c になる最小の c
	auto u = ( d == 0 ) ? long.max : 10 / d + ( 0 < 10 % d );
	
	if( c < u )
	{
		// 繰り上がりなしの場合
		
		// 全桁足し算する
		ds ~= d * c;
		t += c - 1;
	}
	else
	{
		// 繰り上がりありの場合
		
		// 繰り上がりが発生する分を1桁になるまで足し算する
		{
			auto r = solve2( ( d * u ) % 10 + 1, c / u );
			ds ~= r[ 0 ];
			t += r[ 1 ] + ( c - c % u );
		}
		
		// 繰り上がりが発生しない分を1桁になるまで足し算する
		if( 0 < c % u )
		{
			auto r = solve2( d, c % u );
			ds ~= r[ 0 ];
			t += r[ 1 ];
		}
	}
	
	return tuple( ds, t );
}
