





from __future__ import annotations

from math import ceil, floor, sqrt



def      __lowercase     (   _SCREAMING_SNAKE_CASE = 2_00_00_00			)				->     int:


      '''simple docstring'''


      SCREAMING_SNAKE_CASE	=		[0]
      SCREAMING_SNAKE_CASE	=		42

      for idx in range(1				,		ceil(sqrt(target * 2			) * 1.1			)			):
            triangle_numbers.append(triangle_numbers[-1] + idx			)

      # we want this to be as close as possible to target
      SCREAMING_SNAKE_CASE	=		0
      # the area corresponding to the grid that gives the product closest to target
      SCREAMING_SNAKE_CASE	=		0
      # an estimate of b, using the quadratic formula
      SCREAMING_SNAKE_CASE	=		42
      # the largest integer less than b_estimate
      SCREAMING_SNAKE_CASE	=		42
      # the largest integer less than b_estimate
      SCREAMING_SNAKE_CASE	=		42
      # the triangle number corresponding to b_floor
      SCREAMING_SNAKE_CASE	=		42
      # the triangle number corresponding to b_ceil
      SCREAMING_SNAKE_CASE	=		42

      for idx_a, triangle_a in enumerate(triangle_numbers[1:]				,		1			):
            SCREAMING_SNAKE_CASE	=		(-1 + sqrt(1 + 8 * target / triangle_a			)) / 2
            SCREAMING_SNAKE_CASE	=		floor(_SCREAMING_SNAKE_CASE			)
            SCREAMING_SNAKE_CASE	=		ceil(_SCREAMING_SNAKE_CASE			)
            SCREAMING_SNAKE_CASE	=		triangle_numbers[b_floor]
            SCREAMING_SNAKE_CASE	=		triangle_numbers[b_ceil]

            if abs(target - triangle_b_first_guess * triangle_a			) < abs(
                target - best_product			):
                  SCREAMING_SNAKE_CASE	=		triangle_b_first_guess * triangle_a
                  SCREAMING_SNAKE_CASE	=		idx_a * b_floor

            if abs(target - triangle_b_second_guess * triangle_a			) < abs(
                target - best_product			):
                  SCREAMING_SNAKE_CASE	=		triangle_b_second_guess * triangle_a
                  SCREAMING_SNAKE_CASE	=		idx_a * b_ceil

      return area


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









# We ignore warnings about stepping the scheduler since we step it ourselves during gradient accumulation

import warnings

from .state import AcceleratorState, GradientState


warnings.filterwarnings("""ignore""", category=UserWarning, module="""torch.optim.lr_scheduler""")

class 	UpperCamelCase__				:



     '''simple docstring'''

     def __init__(							self		:					Optional[Any]		,lowerCamelCase__		:					Optional[int]		,lowerCamelCase__		:					Tuple		,lowerCamelCase__		:					bool = True		,lowerCamelCase__		:					bool = False )  ->	Tuple:




           '''simple docstring'''


           SCREAMING_SNAKE_CASE	=		scheduler
           SCREAMING_SNAKE_CASE	=		optimizers if isinstance(lowerCamelCase__		,(list, tuple) ) else [optimizers]
           SCREAMING_SNAKE_CASE	=		split_batches
           SCREAMING_SNAKE_CASE	=		step_with_optimizer
           SCREAMING_SNAKE_CASE	=		GradientState()






     def        SCREAMING_SNAKE_CASE__						(							self		:					str		,*lowerCamelCase__		:					Union[str, Any]		,**lowerCamelCase__		:					Optional[int] )  ->	Dict:




           '''simple docstring'''


           if not self.step_with_optimizer:
                 # No link between scheduler and optimizer -> just step
                 self.scheduler.step(*lowerCamelCase__		,**lowerCamelCase__ )
                 return

           # Otherwise, first make sure the optimizer was stepped.
           if not self.gradient_state.sync_gradients:
                 if self.gradient_state.adjust_scheduler:
                       self.scheduler._step_count += 1
                 return

           for opt in self.optimizers:
                 if opt.step_was_skipped:
                       return
           if self.split_batches:
                 # Split batches -> the training dataloader batch size is not changed so one step per training step
                 self.scheduler.step(*lowerCamelCase__		,**lowerCamelCase__ )
           else:
                 # Otherwise the training dataloader batch size was multiplied by `num_processes`, so we need to do
                 # num_processes steps per training step
                 SCREAMING_SNAKE_CASE	=		AcceleratorState().num_processes
                 for _ in range(lowerCamelCase__ ):
                       # Special case when using OneCycle and `drop_last` was not used
                       if hasattr(self.scheduler		,"""total_steps""" ):
                             if self.scheduler._step_count <= self.scheduler.total_steps:
                                   self.scheduler.step(*lowerCamelCase__		,**lowerCamelCase__ )
                       else:
                             self.scheduler.step(*lowerCamelCase__		,**lowerCamelCase__ )






     def        SCREAMING_SNAKE_CASE__						(							self		:					int )  ->	Optional[Any]:




           '''simple docstring'''


           return self.scheduler.get_last_lr()






     def        SCREAMING_SNAKE_CASE__						(							self		:					List[Any] )  ->	Optional[Any]:




           '''simple docstring'''


           return self.scheduler.state_dict()






     def        SCREAMING_SNAKE_CASE__						(							self		:					Optional[int]		,lowerCamelCase__		:					str )  ->	int:




           '''simple docstring'''


           self.scheduler.load_state_dict(lowerCamelCase__ )






     def        SCREAMING_SNAKE_CASE__						(							self		:					List[Any] )  ->	Optional[Any]:




           '''simple docstring'''


           return self.scheduler.get_lr()






     def        SCREAMING_SNAKE_CASE__						(							self		:					Dict		,*lowerCamelCase__		:					int		,**lowerCamelCase__		:					Tuple )  ->	Optional[int]:




           '''simple docstring'''


           return self.scheduler.print_lr(*lowerCamelCase__		,**lowerCamelCase__ )


