






__lowerCamelCase :      Any										=				range(2, 20 + 1)
__lowerCamelCase :      List[Any]										=				[10**k for k in range(ks[-1] + 1)]
__lowerCamelCase :      dict[int, dict[int, list[list[int]]]]										=				{}







def 					SCREAMING_SNAKE_CASE    (			snake_case_ :							List[Any]					,  snake_case_ :							List[str]					,  snake_case_ :							Optional[int]					,  snake_case_ :							Any       ):
	snake_case__			:				Optional[int]       =  sum(a_i[j] for j in range(snake_case_					,  len(snake_case_       )       )       )
	snake_case__			:				List[Any]       =  sum(a_i[j] * base[j] for j in range(min(len(snake_case_       )					,  snake_case_       )       )       )

	snake_case__,						snake_case__			:				int       =  0, 0
	snake_case__			:				Optional[int]       =  n - i

	snake_case__			:				int       =  memo.get(snake_case_       )

	if sub_memo is not None:
		snake_case__			:				List[Any]       =  sub_memo.get(snake_case_       )

		if jumps is not None and len(snake_case_       ) > 0:
			# find and make the largest jump without going over
			snake_case__			:				Any       =  -1
			for _k in range(len(snake_case_       ) - 1					,  -1					,  -1       ):
				if jumps[_k][2] <= k and jumps[_k][1] <= max_dn:
					snake_case__			:				str       =  _k
					break

			if max_jump >= 0:
				snake_case__,						snake_case__,						snake_case__			:				Union[str, Any]       =  jumps[max_jump]
				# since the difference between jumps is cached, add c
				snake_case__			:				int       =  diff + c
				for j in range(min(snake_case_					,  len(snake_case_       )       )       ):
					snake_case__,						snake_case__			:				List[Any]       =  divmod(snake_case_					,  10       )
				if new_c > 0:
					add(snake_case_					,  snake_case_					,  snake_case_       )

		else:
			snake_case__			:				Optional[Any]       =  []
	else:
		snake_case__			:				str       =  {c: []}
		snake_case__			:				int       =  sub_memo

	if dn >= max_dn or c + diff >= base[k]:
		return diff, dn

	if k > ks[0]:
		while True:
			# keep doing smaller jumps
			snake_case__,						snake_case__			:				Dict       =  next_term(snake_case_					,  k - 1					,  i + dn					,  snake_case_       )
			diff += _diff
			dn += terms_jumped

			if dn >= max_dn or c + diff >= base[k]:
				break
	else:
		# would be too small a jump, just compute sequential terms instead
		snake_case__,						snake_case__			:				Optional[int]       =  compute(snake_case_					,  snake_case_					,  i + dn					,  snake_case_       )
		diff += _diff
		dn += terms_jumped

	snake_case__			:				Tuple       =  sub_memo[c]

	# keep jumps sorted by # of terms skipped
	snake_case__			:				int       =  0
	while j < len(snake_case_       ):
		if jumps[j][1] > dn:
			break
		j += 1

	# cache the jump for this value digitsum(b) and c
	sub_memo[c].insert(snake_case_					,  (diff, dn, k)       )
	return (diff, dn)







def 					SCREAMING_SNAKE_CASE    (			snake_case_ :							Tuple					,  snake_case_ :							List[Any]					,  snake_case_ :							Optional[int]					,  snake_case_ :							str       ):
	if i >= n:
		return 0, i
	if k > len(snake_case_       ):
		a_i.extend([0 for _ in range(k - len(snake_case_       )       )]       )

	# note: a_i -> b * 10^k + c
	# ds_b -> digitsum(b)
	# ds_c -> digitsum(c)
	snake_case__			:				int       =  i
	snake_case__,						snake_case__,						snake_case__			:				str       =  0, 0, 0
	for j in range(len(snake_case_       )       ):
		if j >= k:
			ds_b += a_i[j]
		else:
			ds_c += a_i[j]

	while i < n:
		i += 1
		snake_case__			:				Tuple       =  ds_c + ds_b
		diff += addend
		snake_case__			:				Optional[int]       =  0
		for j in range(snake_case_       ):
			snake_case__			:				Optional[int]       =  a_i[j] + addend
			snake_case__,						snake_case__			:				str       =  divmod(snake_case_					,  10       )

			ds_c += a_i[j]

		if addend > 0:
			break

	if addend > 0:
		add(snake_case_					,  snake_case_					,  snake_case_       )
	return diff, i - start_i







def 					SCREAMING_SNAKE_CASE    (			snake_case_ :							Tuple					,  snake_case_ :							List[str]					,  snake_case_ :							Tuple       ):
	for j in range(snake_case_					,  len(snake_case_       )       ):
		snake_case__			:				Optional[int]       =  digits[j] + addend
		if s >= 10:
			snake_case__,						snake_case__			:				Any       =  divmod(snake_case_					,  10       )
			snake_case__			:				List[Any]       =  addend // 10 + quotient
		else:
			snake_case__			:				List[Any]       =  s
			snake_case__			:				Optional[int]       =  addend // 10

		if addend == 0:
			break

	while addend > 0:
		snake_case__,						snake_case__			:				Optional[int]       =  divmod(snake_case_					,  10       )
		digits.append(snake_case_       )







def 					SCREAMING_SNAKE_CASE    (			snake_case_ :							int = 10**15       ):
	snake_case__			:				List[str]       =  [1]
	snake_case__			:				Tuple       =  1
	snake_case__			:				Optional[Any]       =  0
	while True:
		snake_case__,						snake_case__			:				List[Any]       =  next_term(snake_case_					,  20					,  i + dn					,  snake_case_       )
		dn += terms_jumped
		if dn == n - i:
			break

	snake_case__			:				Any       =  0
	for j in range(len(snake_case_       )       ):
		a_n += digits[j] * 10**j
	return a_n


if __name__ == "__main__":
	print(f"{solution() = }")











from tempfile import TemporaryDirectory
from unittest import TestCase
from unittest.mock import MagicMock, patch

from transformers import AutoModel, TFAutoModel
from transformers.onnx import FeaturesManager
from transformers.testing_utils import SMALL_MODEL_IDENTIFIER, require_tf, require_torch



@require_torch
@require_tf
class 							SCREAMING_SNAKE_CASE__						(    UpperCamelCase_						):





					"""simple docstring"""






					def 	_lowercase					( self					:  Optional[Any]	):
						snake_case__			:				Optional[Any]       =  SMALL_MODEL_IDENTIFIER
						snake_case__			:				Any       =  "pt"
						snake_case__			:				Any       =  "tf"



					def 	_lowercase					( self					:  Union[str, Any]							,		__A					:  List[Any]	):
						snake_case__			:				int       =  AutoModel.from_pretrained(self.test_model	)
						model_pt.save_pretrained(__A	)



					def 	_lowercase					( self					:  Optional[int]							,		__A					:  Tuple	):
						snake_case__			:				List[Any]       =  TFAutoModel.from_pretrained(self.test_model							,		from_pt=__A	)
						model_tf.save_pretrained(__A	)



					def 	_lowercase					( self					:  str	):
						snake_case__			:				Optional[Any]       =  "mock_framework"

						# Framework provided - return whatever the user provides
						snake_case__			:				Optional[Any]       =  FeaturesManager.determine_framework(self.test_model							,		__A	)
						self.assertEqual(__A							,		__A	)

						# Local checkpoint and framework provided - return provided framework
						# PyTorch checkpoint
						with TemporaryDirectory() as local_pt_ckpt:
							self._setup_pt_ckpt(__A	)
							snake_case__			:				Optional[int]       =  FeaturesManager.determine_framework(__A							,		__A	)
							self.assertEqual(__A							,		__A	)

						# TensorFlow checkpoint
						with TemporaryDirectory() as local_tf_ckpt:
							self._setup_tf_ckpt(__A	)
							snake_case__			:				int       =  FeaturesManager.determine_framework(__A							,		__A	)
							self.assertEqual(__A							,		__A	)



					def 	_lowercase					( self					:  Dict	):
						# PyTorch checkpoint
						with TemporaryDirectory() as local_pt_ckpt:
							self._setup_pt_ckpt(__A	)
							snake_case__			:				List[str]       =  FeaturesManager.determine_framework(__A	)
							self.assertEqual(__A							,		self.framework_pt	)

						# TensorFlow checkpoint
						with TemporaryDirectory() as local_tf_ckpt:
							self._setup_tf_ckpt(__A	)
							snake_case__			:				Tuple       =  FeaturesManager.determine_framework(__A	)
							self.assertEqual(__A							,		self.framework_tf	)

						# Invalid local checkpoint
						with TemporaryDirectory() as local_invalid_ckpt:
							with self.assertRaises(__A	):
								snake_case__			:				int       =  FeaturesManager.determine_framework(__A	)






					def 	_lowercase					( self					:  Dict	):
						snake_case__			:				Dict       =  MagicMock(return_value=__A	)
						with patch("transformers.onnx.features.is_tf_available"							,		__A	):
							snake_case__			:				List[Any]       =  FeaturesManager.determine_framework(self.test_model	)
							self.assertEqual(__A							,		self.framework_pt	)

						# PyTorch not in environment -> use TensorFlow
						snake_case__			:				Tuple       =  MagicMock(return_value=__A	)
						with patch("transformers.onnx.features.is_torch_available"							,		__A	):
							snake_case__			:				int       =  FeaturesManager.determine_framework(self.test_model	)
							self.assertEqual(__A							,		self.framework_tf	)

						# Both in environment -> use PyTorch
						snake_case__			:				Dict       =  MagicMock(return_value=__A	)
						snake_case__			:				Optional[int]       =  MagicMock(return_value=__A	)
						with patch("transformers.onnx.features.is_tf_available"							,		__A	), patch(
						    "transformers.onnx.features.is_torch_available"							,		__A	):
							snake_case__			:				Optional[Any]       =  FeaturesManager.determine_framework(self.test_model	)
							self.assertEqual(__A							,		self.framework_pt	)

						# Both not in environment -> raise error
						snake_case__			:				List[str]       =  MagicMock(return_value=__A	)
						snake_case__			:				Optional[Any]       =  MagicMock(return_value=__A	)
						with patch("transformers.onnx.features.is_tf_available"							,		__A	), patch(
						    "transformers.onnx.features.is_torch_available"							,		__A	):
							with self.assertRaises(__A	):
								snake_case__			:				Optional[Any]       =  FeaturesManager.determine_framework(self.test_model	)



