├── .github └── workflows │ ├── benchmarks.yml │ ├── python-package-36.yml │ └── python-package.yml ├── .gitignore ├── .readthedocs.yaml ├── LICENSE ├── README.md ├── README_ja.md ├── asv.conf.json ├── atcoder ├── __init__.py ├── __main__.py ├── _bit.py ├── _math.py ├── _scc.py ├── convolution.py ├── dsu.py ├── fenwicktree.py ├── lazysegtree.py ├── math.py ├── maxflow.py ├── mincostflow.py ├── modint.py ├── scc.py ├── segtree.py ├── string.py └── twosat.py ├── benchmarks ├── __init__.py └── benchmark_dsu.py ├── docs ├── Makefile ├── _templates │ └── autosummary │ │ └── class.rst ├── conf.py ├── convolution.rst ├── dsu.rst ├── fenwicktree.rst ├── index.rst ├── lazysegtree.rst ├── make.bat ├── math.rst ├── maxflow.rst ├── mincostflow.rst ├── modint.rst ├── scc.rst ├── segtree.rst ├── string.rst └── twosat.rst ├── example ├── __init__.py ├── convolution_practice.py ├── convolution_practice_int.py ├── dsu_practice.py ├── fenwick_practice.py ├── floor_sum_practice.py ├── lazysegtree_practice_k.py ├── lazysegtree_practice_k_wo_modint.py ├── lazysegtree_practice_l.py ├── maxflow_practice.py ├── mincostflow_practice.py ├── sa_practice.py ├── scc_practice.py ├── segtree_practice.py ├── segtree_practice_reversed.py └── twosat_practice.py ├── setup.cfg ├── setup.py └── tests ├── __init__.py ├── example_tests ├── __init__.py ├── input │ ├── A1_in.txt │ ├── A1_out.txt │ ├── B1_in.txt │ ├── B1_out.txt │ ├── C1_in.txt │ ├── C1_out.txt │ ├── D1_in.txt │ ├── D1_out.txt │ ├── E1_in.txt │ ├── E1_out.txt │ ├── E2_in.txt │ ├── E2_out.txt │ ├── F1_in.txt │ ├── F1_out.txt │ ├── F2_in.txt │ ├── F2_out.txt │ ├── G1_in.txt │ ├── G1_out.txt │ ├── H1_in.txt │ ├── H1_out.txt │ ├── H2_in.txt │ ├── H2_out.txt │ ├── I1_in.txt │ ├── I1_out.txt │ ├── I2_in.txt │ ├── I2_out.txt │ ├── I3_in.txt │ ├── I3_out.txt │ ├── I4_in.txt │ ├── I4_out.txt │ ├── J1_in.txt │ ├── J1_out.txt │ ├── K1_in.txt │ ├── K1_out.txt │ ├── L1_in.txt │ └── L1_out.txt └── test_examples.py ├── test__bit.py ├── test_dsu.py ├── test_fenwicktree.py ├── test_internal_math.py └── test_math.py /.github/workflows/benchmarks.yml: -------------------------------------------------------------------------------- 1 | name: Benchmarks 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v4 13 | - name: Set up Python 3.13 14 | uses: actions/setup-python@v5 15 | with: 16 | python-version: 3.13 17 | - name: Install dependencies 18 | run: | 19 | python -m pip install --upgrade pip 20 | pip install .[benchmark] 21 | - name: Benchmark with asv 22 | run: | 23 | asv machine --yes 24 | asv run 25 | -------------------------------------------------------------------------------- /.github/workflows/python-package-36.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions 3 | 4 | name: Python package 5 | 6 | on: 7 | push: 8 | branches: [master] 9 | pull_request: 10 | branches: [master] 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-20.04 15 | strategy: 16 | matrix: 17 | python-version: ['3.6'] 18 | 19 | steps: 20 | - uses: actions/checkout@v4 21 | - name: Set up Python ${{ matrix.python-version }} 22 | uses: actions/setup-python@v5 23 | with: 24 | python-version: ${{ matrix.python-version }} 25 | - name: Install dependencies 26 | run: | 27 | python -m pip install --upgrade pip 28 | pip install .[lint,test] 29 | - name: Lint with flake8 30 | run: | 31 | # stop the build if there are Python syntax errors or undefined names 32 | flake8 atcoder tests --count --select=E9,F63,F7,F82 --show-source --statistics 33 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide 34 | flake8 atcoder tests --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics 35 | - name: Type check with mypy 36 | run: | 37 | mypy atcoder tests 38 | - name: Test with pytest 39 | run: | 40 | pytest 41 | -------------------------------------------------------------------------------- /.github/workflows/python-package.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions 3 | 4 | name: Python package 5 | 6 | on: 7 | push: 8 | branches: [master] 9 | pull_request: 10 | branches: [master] 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | strategy: 16 | matrix: 17 | python-version: ['3.7', '3.8', '3.9', '3.10', '3.11', '3.12', '3.13'] 18 | 19 | steps: 20 | - uses: actions/checkout@v4 21 | - name: Set up Python ${{ matrix.python-version }} 22 | uses: actions/setup-python@v5 23 | with: 24 | python-version: ${{ matrix.python-version }} 25 | - name: Install dependencies 26 | run: | 27 | python -m pip install --upgrade pip 28 | pip install .[lint,test] 29 | - name: Lint with flake8 30 | run: | 31 | # stop the build if there are Python syntax errors or undefined names 32 | flake8 atcoder tests --count --select=E9,F63,F7,F82 --show-source --statistics 33 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide 34 | flake8 atcoder tests --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics 35 | - name: Type check with mypy 36 | run: | 37 | mypy atcoder tests 38 | - name: Test with pytest 39 | run: | 40 | pytest 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | docs/generated/ 74 | 75 | # PyBuilder 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | .python-version 87 | 88 | # pipenv 89 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 90 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 91 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 92 | # install all needed dependencies. 93 | #Pipfile.lock 94 | 95 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 96 | __pypackages__/ 97 | 98 | # Celery stuff 99 | celerybeat-schedule 100 | celerybeat.pid 101 | 102 | # SageMath parsed files 103 | *.sage.py 104 | 105 | # Environments 106 | .env 107 | .venv 108 | env/ 109 | venv/ 110 | ENV/ 111 | env.bak/ 112 | venv.bak/ 113 | 114 | # Spyder project settings 115 | .spyderproject 116 | .spyproject 117 | 118 | # Rope project settings 119 | .ropeproject 120 | 121 | # mkdocs documentation 122 | /site 123 | 124 | # mypy 125 | .mypy_cache/ 126 | .dmypy.json 127 | dmypy.json 128 | 129 | # Pyre type checker 130 | .pyre/ 131 | 132 | # asv 133 | .asv 134 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | build: 4 | os: ubuntu-22.04 5 | tools: 6 | python: "3.12" 7 | 8 | sphinx: 9 | configuration: docs/conf.py 10 | 11 | python: 12 | install: 13 | - method: pip 14 | path: . 15 | extra_requirements: 16 | - docs 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | CC0 1.0 Universal 2 | 3 | Statement of Purpose 4 | 5 | The laws of most jurisdictions throughout the world automatically confer 6 | exclusive Copyright and Related Rights (defined below) upon the creator and 7 | subsequent owner(s) (each and all, an "owner") of an original work of 8 | authorship and/or a database (each, a "Work"). 9 | 10 | Certain owners wish to permanently relinquish those rights to a Work for the 11 | purpose of contributing to a commons of creative, cultural and scientific 12 | works ("Commons") that the public can reliably and without fear of later 13 | claims of infringement build upon, modify, incorporate in other works, reuse 14 | and redistribute as freely as possible in any form whatsoever and for any 15 | purposes, including without limitation commercial purposes. These owners may 16 | contribute to the Commons to promote the ideal of a free culture and the 17 | further production of creative, cultural and scientific works, or to gain 18 | reputation or greater distribution for their Work in part through the use and 19 | efforts of others. 20 | 21 | For these and/or other purposes and motivations, and without any expectation 22 | of additional consideration or compensation, the person associating CC0 with a 23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright 24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work 25 | and publicly distribute the Work under its terms, with knowledge of his or her 26 | Copyright and Related Rights in the Work and the meaning and intended legal 27 | effect of CC0 on those rights. 28 | 29 | 1. Copyright and Related Rights. A Work made available under CC0 may be 30 | protected by copyright and related or neighboring rights ("Copyright and 31 | Related Rights"). Copyright and Related Rights include, but are not limited 32 | to, the following: 33 | 34 | i. the right to reproduce, adapt, distribute, perform, display, communicate, 35 | and translate a Work; 36 | 37 | ii. moral rights retained by the original author(s) and/or performer(s); 38 | 39 | iii. publicity and privacy rights pertaining to a person's image or likeness 40 | depicted in a Work; 41 | 42 | iv. rights protecting against unfair competition in regards to a Work, 43 | subject to the limitations in paragraph 4(a), below; 44 | 45 | v. rights protecting the extraction, dissemination, use and reuse of data in 46 | a Work; 47 | 48 | vi. database rights (such as those arising under Directive 96/9/EC of the 49 | European Parliament and of the Council of 11 March 1996 on the legal 50 | protection of databases, and under any national implementation thereof, 51 | including any amended or successor version of such directive); and 52 | 53 | vii. other similar, equivalent or corresponding rights throughout the world 54 | based on applicable law or treaty, and any national implementations thereof. 55 | 56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of, 57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and 58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright 59 | and Related Rights and associated claims and causes of action, whether now 60 | known or unknown (including existing as well as future claims and causes of 61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum 62 | duration provided by applicable law or treaty (including future time 63 | extensions), (iii) in any current or future medium and for any number of 64 | copies, and (iv) for any purpose whatsoever, including without limitation 65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes 66 | the Waiver for the benefit of each member of the public at large and to the 67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver 68 | shall not be subject to revocation, rescission, cancellation, termination, or 69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work 70 | by the public as contemplated by Affirmer's express Statement of Purpose. 71 | 72 | 3. Public License Fallback. Should any part of the Waiver for any reason be 73 | judged legally invalid or ineffective under applicable law, then the Waiver 74 | shall be preserved to the maximum extent permitted taking into account 75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver 76 | is so judged Affirmer hereby grants to each affected person a royalty-free, 77 | non transferable, non sublicensable, non exclusive, irrevocable and 78 | unconditional license to exercise Affirmer's Copyright and Related Rights in 79 | the Work (i) in all territories worldwide, (ii) for the maximum duration 80 | provided by applicable law or treaty (including future time extensions), (iii) 81 | in any current or future medium and for any number of copies, and (iv) for any 82 | purpose whatsoever, including without limitation commercial, advertising or 83 | promotional purposes (the "License"). The License shall be deemed effective as 84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the 85 | License for any reason be judged legally invalid or ineffective under 86 | applicable law, such partial invalidity or ineffectiveness shall not 87 | invalidate the remainder of the License, and in such case Affirmer hereby 88 | affirms that he or she will not (i) exercise any of his or her remaining 89 | Copyright and Related Rights in the Work or (ii) assert any associated claims 90 | and causes of action with respect to the Work, in either case contrary to 91 | Affirmer's express Statement of Purpose. 92 | 93 | 4. Limitations and Disclaimers. 94 | 95 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 96 | surrendered, licensed or otherwise affected by this document. 97 | 98 | b. Affirmer offers the Work as-is and makes no representations or warranties 99 | of any kind concerning the Work, express, implied, statutory or otherwise, 100 | including without limitation warranties of title, merchantability, fitness 101 | for a particular purpose, non infringement, or the absence of latent or 102 | other defects, accuracy, or the present or absence of errors, whether or not 103 | discoverable, all to the greatest extent permissible under applicable law. 104 | 105 | c. Affirmer disclaims responsibility for clearing rights of other persons 106 | that may apply to the Work or any use thereof, including without limitation 107 | any person's Copyright and Related Rights in the Work. Further, Affirmer 108 | disclaims responsibility for obtaining any necessary consents, permissions 109 | or other rights required for any use of the Work. 110 | 111 | d. Affirmer understands and acknowledges that Creative Commons is not a 112 | party to this document and has no duty or obligation with respect to this 113 | CC0 or use of the Work. 114 | 115 | For more information, please see 116 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ac-library-python 2 | 3 | [日本語のREADME](README_ja.md) 4 | 5 | ## Description 6 | 7 | ac-library-python is a Python port of [AtCoder Library (ACL)](https://atcoder.jp/posts/517). For more information, see [References](#References). 8 | 9 | ## Progress 10 | 11 | All features are ported but may contain bugs. Some of them need to be improved speed, especially `modint` and `lazysegtree`. 12 | 13 | We are working on adding unit tests and documents. 14 | 15 | 16 | ## Install 17 | 18 | ``` 19 | pip install git+https://github.com/not522/ac-library-python 20 | ``` 21 | 22 | ## Usage 23 | 24 | The following command outputs a single combined code which can run in online judge systems. 25 | 26 | ``` 27 | python -m atcoder [your-source-code] -o [single-combined-code] 28 | ``` 29 | 30 | ## FAQ 31 | 32 | + Comming soon. 33 | 34 | ## Requirement 35 | 36 | ### For all users 37 | 38 | + Python 3.6.0+, 3.7.0+, 3.8.0+ 39 | + pip 40 | 41 | ### For developer 42 | 43 | #### Test framework and CI 44 | 45 | + [Pytest](https://docs.pytest.org/en/stable/) 46 | + [GitHub Actions](https://docs.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions) 47 | 48 | #### Lint 49 | 50 | + [flake8](https://pypi.org/project/flake8/) 51 | + [pep8-naming](https://pypi.org/project/pep8-naming/) 52 | + [mypy](https://pypi.org/project/mypy/) 53 | 54 | ## How to contribute 55 | 56 | + Comming soon. 57 | 58 | ## References 59 | 60 | [AtCoder Library (ACL) - AtCoder](https://atcoder.jp/posts/517) 61 | 62 | [AtCoder Library - Codeforces](https://codeforces.com/blog/entry/82400) 63 | 64 | [AtCoder Library (ACL) - GitHub repository](https://github.com/atcoder/ac-library) 65 | 66 | ## Related Projects 67 | 68 | [ac-library-c](https://github.com/siumai1223/ac-library-c) - C port. 69 | 70 | [single-file-ac-library](https://github.com/TumoiYorozu/single-file-ac-library) - [The official library](https://atcoder.jp/posts/517) is made available as a single file. You can also view [the official documentation](https://tumoiyorozu.github.io/single-file-ac-library/document_ja/) in your favorite browser. 71 | 72 | [ac-library-cs](https://github.com/key-moon/ac-library-cs) - C# port. 73 | 74 | [ac-library-d](https://github.com/arkark/ac-library-d) - D port. 75 | 76 | [ac-library-go](https://github.com/monkukui/ac-library-go) - Go port. 77 | 78 | [AtCoderLibraryForJava](https://github.com/NASU41/AtCoderLibraryForJava) - Java port. 79 | 80 | [ACL.jl](https://github.com/abap34/ACL.jl) - Julia port. 81 | 82 | [ac-library-kt](https://github.com/da-louis/ac-library-kt) - Kotlin port. This project is based on [Java port](https://github.com/NASU41/AtCoderLibraryForJava). 83 | 84 | [Nim-ACL](https://github.com/zer0-star/Nim-ACL) - Nim port. 85 | 86 | [ACL-Python](https://github.com/Mitarushi/ACL-Python) - PyPy port. 87 | 88 | [ac-library-ruby](https://github.com/universato/ac-library-rb) - Ruby port. 89 | 90 | [ac-library-rs](https://github.com/rust-lang-ja/ac-library-rs) - Rust port. 91 | 92 | ## LICENSE 93 | 94 | [CC0](https://creativecommons.org/share-your-work/public-domain/cc0) 95 | -------------------------------------------------------------------------------- /README_ja.md: -------------------------------------------------------------------------------- 1 | # ac-library-python 2 | 3 | ## 説明 4 | 5 | ac-library-pythonは、[AtCoder Library (ACL)](https://atcoder.jp/posts/517)のPython移植版です。 詳しくは、[公式情報](#公式情報)をご参照ください. 6 | 7 | ## 進捗状況 8 | 9 | 移植は完了していますが、まだバグが残っている可能性があります。また、`modint`や`lazysegtree`などのライブラリは速度の改善が必要です。 10 | 11 | 現在、単体テストとドキュメントの追加を行っています。 12 | 13 | ## インストール 14 | 15 | ``` 16 | pip install git+https://github.com/not522/ac-library-python 17 | ``` 18 | 19 | ## 使い方 20 | 21 | 以下のコマンドでオンラインジャッジで実行可能な結合されたソースコードが出力されます。 22 | 23 | ``` 24 | python -m atcoder [your-source-code] -o [single-combined-code] 25 | ``` 26 | 27 | ## よくある質問 28 | 29 | + 準備中。 30 | 31 | ## 利用環境、開発環境に関する情報 32 | 33 | ### 利用者、開発者向け情報 34 | 35 | + Python 3.6.0+, 3.7.0+, 3.8.0+ 36 | + pip 37 | 38 | ### 開発者向け情報 39 | 40 | #### テストフレームワーク、CI 41 | 42 | + [Pytest](https://docs.pytest.org/en/stable/) 43 | + [GitHub Actions](https://docs.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions) 44 | 45 | #### Lint 46 | 47 | + [flake8](https://pypi.org/project/flake8/) 48 | + [pep8-naming](https://pypi.org/project/pep8-naming/) 49 | + [mypy](https://pypi.org/project/mypy/) 50 | 51 | ## 本レポジトリに貢献する方法 52 | 53 | + 準備中。 54 | 55 | ## 公式情報 56 | 57 | [AtCoder Library (ACL) - AtCoder](https://atcoder.jp/posts/517) 58 | 59 | [AtCoder Library - Codeforces](https://codeforces.com/blog/entry/82400) 60 | 61 | [AtCoder Library (ACL)のGitHubレポジトリ](https://github.com/atcoder/ac-library) 62 | 63 | ## 関連プロジェクト 64 | 65 | [ac-library-c](https://github.com/siumai1223/ac-library-c) - C版。 66 | 67 | [single-file-ac-library](https://github.com/TumoiYorozu/single-file-ac-library) - [公式ライブラリ](https://atcoder.jp/posts/517)を一つのファイルにまとめて利用できます。また、[公式ドキュメント](https://tumoiyorozu.github.io/single-file-ac-library/document_ja/)をブラウザで見ることもできます。 68 | 69 | [ac-library-cs](https://github.com/key-moon/ac-library-cs) - C#版。 70 | 71 | [ac-library-d](https://github.com/arkark/ac-library-d) - D版。 72 | 73 | [ac-library-go](https://github.com/monkukui/ac-library-go) - Go版。 74 | 75 | [AtCoderLibraryForJava](https://github.com/NASU41/AtCoderLibraryForJava) - Java版。 76 | 77 | [ACL.jl](https://github.com/abap34/ACL.jl) - Julia版。 78 | 79 | [ac-library-kt](https://github.com/da-louis/ac-library-kt) - Kotlin版。[AtCoderLibraryForJava](https://github.com/NASU41/AtCoderLibraryForJava)に基づいて作成されています。 80 | 81 | [Nim-ACL](https://github.com/zer0-star/Nim-ACL) - Nim版。 82 | 83 | [ACL-Python](https://github.com/Mitarushi/ACL-Python) - PyPy版。 84 | 85 | [ac-library-ruby](https://github.com/universato/ac-library-rb) - Ruby版。 86 | 87 | [ac-library-rs](https://github.com/rust-lang-ja/ac-library-rs) - Rust版。 88 | 89 | ## ライセンス 90 | 91 | [CC0](https://creativecommons.org/share-your-work/public-domain/cc0) 92 | -------------------------------------------------------------------------------- /asv.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | // The version of the config file format. Do not change, unless 3 | // you know what you are doing. 4 | "version": 1, 5 | 6 | // The name of the project being benchmarked 7 | "project": "ac-library-python", 8 | 9 | // The project's homepage 10 | "project_url": "https://github.com/not522/ac-library-python", 11 | 12 | // The URL or local path of the source code repository for the 13 | // project being benchmarked 14 | "repo": ".", 15 | 16 | // The Python project's subdirectory in your repo. If missing or 17 | // the empty string, the project is assumed to be located at the root 18 | // of the repository. 19 | // "repo_subdir": "", 20 | 21 | // Customizable commands for building, installing, and 22 | // uninstalling the project. See asv.conf.json documentation. 23 | // 24 | // "install_command": ["in-dir={env_dir} python -mpip install {wheel_file}"], 25 | // "uninstall_command": ["return-code=any python -mpip uninstall -y {project}"], 26 | // "build_command": [ 27 | // "python setup.py build", 28 | // "PIP_NO_BUILD_ISOLATION=false python -mpip wheel --no-deps --no-index -w {build_cache_dir} {build_dir}" 29 | // ], 30 | 31 | // List of branches to benchmark. If not provided, defaults to "master" 32 | // (for git) or "default" (for mercurial). 33 | // "branches": ["master"], // for git 34 | // "branches": ["default"], // for mercurial 35 | 36 | // The DVCS being used. If not set, it will be automatically 37 | // determined from "repo" by looking at the protocol in the URL 38 | // (if remote), or by looking for special directories, such as 39 | // ".git" (if local). 40 | // "dvcs": "git", 41 | 42 | // The tool to use to create environments. May be "conda", 43 | // "virtualenv" or other value depending on the plugins in use. 44 | // If missing or the empty string, the tool will be automatically 45 | // determined by looking for tools on the PATH environment 46 | // variable. 47 | "environment_type": "virtualenv", 48 | 49 | // timeout in seconds for installing any dependencies in environment 50 | // defaults to 10 min 51 | //"install_timeout": 600, 52 | 53 | // the base URL to show a commit for the project. 54 | "show_commit_url": "https://github.com/not522/ac-library-python/commit/", 55 | 56 | // The Pythons you'd like to test against. If not provided, defaults 57 | // to the current version of Python used to run `asv`. 58 | // "pythons": ["2.7", "3.6"], 59 | 60 | // The list of conda channel names to be searched for benchmark 61 | // dependency packages in the specified order 62 | // "conda_channels": ["conda-forge", "defaults"], 63 | 64 | // The matrix of dependencies to test. Each key is the name of a 65 | // package (in PyPI) and the values are version numbers. An empty 66 | // list or empty string indicates to just test against the default 67 | // (latest) version. null indicates that the package is to not be 68 | // installed. If the package to be tested is only available from 69 | // PyPi, and the 'environment_type' is conda, then you can preface 70 | // the package name by 'pip+', and the package will be installed via 71 | // pip (with all the conda available packages installed first, 72 | // followed by the pip installed packages). 73 | // 74 | // "matrix": { 75 | // "numpy": ["1.6", "1.7"], 76 | // "six": ["", null], // test with and without six installed 77 | // "pip+emcee": [""], // emcee is only available for install with pip. 78 | // }, 79 | 80 | // Combinations of libraries/python versions can be excluded/included 81 | // from the set to test. Each entry is a dictionary containing additional 82 | // key-value pairs to include/exclude. 83 | // 84 | // An exclude entry excludes entries where all values match. The 85 | // values are regexps that should match the whole string. 86 | // 87 | // An include entry adds an environment. Only the packages listed 88 | // are installed. The 'python' key is required. The exclude rules 89 | // do not apply to includes. 90 | // 91 | // In addition to package names, the following keys are available: 92 | // 93 | // - python 94 | // Python version, as in the *pythons* variable above. 95 | // - environment_type 96 | // Environment type, as above. 97 | // - sys_platform 98 | // Platform, as in sys.platform. Possible values for the common 99 | // cases: 'linux2', 'win32', 'cygwin', 'darwin'. 100 | // 101 | // "exclude": [ 102 | // {"python": "3.2", "sys_platform": "win32"}, // skip py3.2 on windows 103 | // {"environment_type": "conda", "six": null}, // don't run without six on conda 104 | // ], 105 | // 106 | // "include": [ 107 | // // additional env for python2.7 108 | // {"python": "2.7", "numpy": "1.8"}, 109 | // // additional env if run on windows+conda 110 | // {"platform": "win32", "environment_type": "conda", "python": "2.7", "libpython": ""}, 111 | // ], 112 | 113 | // The directory (relative to the current directory) that benchmarks are 114 | // stored in. If not provided, defaults to "benchmarks" 115 | // "benchmark_dir": "benchmarks", 116 | 117 | // The directory (relative to the current directory) to cache the Python 118 | // environments in. If not provided, defaults to "env" 119 | "env_dir": ".asv/env", 120 | 121 | // The directory (relative to the current directory) that raw benchmark 122 | // results are stored in. If not provided, defaults to "results". 123 | "results_dir": ".asv/results", 124 | 125 | // The directory (relative to the current directory) that the html tree 126 | // should be written to. If not provided, defaults to "html". 127 | "html_dir": ".asv/html", 128 | 129 | // The number of characters to retain in the commit hashes. 130 | // "hash_length": 8, 131 | 132 | // `asv` will cache results of the recent builds in each 133 | // environment, making them faster to install next time. This is 134 | // the number of builds to keep, per environment. 135 | // "build_cache_size": 2, 136 | 137 | // The commits after which the regression search in `asv publish` 138 | // should start looking for regressions. Dictionary whose keys are 139 | // regexps matching to benchmark names, and values corresponding to 140 | // the commit (exclusive) after which to start looking for 141 | // regressions. The default is to start from the first commit 142 | // with results. If the commit is `null`, regression detection is 143 | // skipped for the matching benchmark. 144 | // 145 | // "regressions_first_commits": { 146 | // "some_benchmark": "352cdf", // Consider regressions only after this commit 147 | // "another_benchmark": null, // Skip regression detection altogether 148 | // }, 149 | 150 | // The thresholds for relative change in results, after which `asv 151 | // publish` starts reporting regressions. Dictionary of the same 152 | // form as in ``regressions_first_commits``, with values 153 | // indicating the thresholds. If multiple entries match, the 154 | // maximum is taken. If no entry matches, the default is 5%. 155 | // 156 | // "regressions_thresholds": { 157 | // "some_benchmark": 0.01, // Threshold of 1% 158 | // "another_benchmark": 0.5, // Threshold of 50% 159 | // }, 160 | } 161 | -------------------------------------------------------------------------------- /atcoder/__init__.py: -------------------------------------------------------------------------------- 1 | # Python port of AtCoder Library. 2 | 3 | __version__ = '0.0.1' 4 | -------------------------------------------------------------------------------- /atcoder/__main__.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import ast 3 | import importlib 4 | import inspect 5 | import re 6 | from typing import List, Optional, cast 7 | 8 | 9 | class ImportInfo: 10 | def __init__(self, lineno: int, end_lineno: int, 11 | import_from: Optional[str] = None, 12 | name: Optional[str] = None, 13 | asname: Optional[str] = None) -> None: 14 | self.lineno = lineno 15 | self.end_lineno = end_lineno 16 | self.import_from = import_from 17 | self.name = name 18 | self.asname = asname 19 | 20 | 21 | def iter_child_nodes( 22 | node: ast.AST, 23 | import_info: Optional[ImportInfo] = None) -> List[ImportInfo]: 24 | result = [] 25 | 26 | if isinstance(node, ast.alias): 27 | if import_info: 28 | result.append(ImportInfo( 29 | import_info.lineno, import_info.end_lineno, 30 | import_info.import_from, node.name, node.asname)) 31 | return result 32 | 33 | if isinstance(node, ast.Import): 34 | for name in node.names: 35 | if re.match(r'^atcoder\.?', name.name): 36 | if hasattr(node, 'end_lineno'): 37 | end_lineno = cast(int, node.end_lineno) # type: ignore 38 | else: 39 | end_lineno = node.lineno 40 | import_info = ImportInfo(node.lineno, end_lineno) 41 | elif isinstance(node, ast.ImportFrom): 42 | if re.match(r'^atcoder\.?', cast(str, node.module)): 43 | if hasattr(node, 'end_lineno'): 44 | end_lineno = cast(int, node.end_lineno) # type: ignore 45 | else: 46 | end_lineno = node.lineno 47 | import_info = ImportInfo(node.lineno, end_lineno, node.module) 48 | 49 | for child in ast.iter_child_nodes(node): 50 | result += iter_child_nodes(child, import_info) 51 | return result 52 | 53 | 54 | class ModuleImporter: 55 | def __init__(self) -> None: 56 | self.imported_modules: List[str] = [] 57 | 58 | def import_module(self, import_from: Optional[str], name: str, 59 | asname: Optional[str] = None) -> str: 60 | result = '' 61 | 62 | if import_from is None: 63 | module_name = name 64 | else: 65 | try: 66 | module_name = import_from + '.' + name 67 | importlib.import_module(module_name) 68 | except ImportError: 69 | module_name = import_from 70 | 71 | if module_name not in self.imported_modules: 72 | self.imported_modules.append(module_name) 73 | 74 | module = importlib.import_module(module_name) 75 | source = inspect.getsource(module) 76 | lines = source.split('\n') 77 | imports = iter_child_nodes(ast.parse(source)) 78 | 79 | import_lines = [] 80 | for import_info in imports: 81 | result += self.import_module( 82 | import_info.import_from, cast(str, import_info.name), 83 | import_info.asname) 84 | for line in range(import_info.lineno - 1, 85 | import_info.end_lineno): 86 | import_lines.append(line) 87 | 88 | for lineno, line_str in enumerate(lines): 89 | if lineno not in import_lines: 90 | continue 91 | lines[lineno] = '# ' + line_str # TODO(not): indent 92 | 93 | modules = module_name.split('.') 94 | for i in range(len(modules) - 1): 95 | result += self.import_module(None, '.'.join(modules[:i + 1])) 96 | 97 | code = '_' + module_name.replace('.', '_') + '_code' 98 | result += f'{code} = """\n' 99 | result += '\n'.join(lines) 100 | result += '"""\n\n' 101 | result += f"{module_name} = types.ModuleType('{module_name}')\n" 102 | 103 | # TODO(not): asname 104 | imported = [] 105 | for import_info in imports: 106 | if import_info.import_from is None: 107 | modules = cast(str, import_info.name).split('.') 108 | for i in range(len(modules)): 109 | import_name = '.'.join(modules[:i + 1]) 110 | if import_name in imported: 111 | continue 112 | imported.append(import_name) 113 | result += f"{module_name}.__dict__['{import_name}']" \ 114 | f" = {import_name}\n" 115 | else: 116 | result += f"{module_name}.__dict__['{import_info.name}']" \ 117 | f" = {import_info.import_from}.{import_info.name}\n" 118 | 119 | result += f'exec({code}, {module_name}.__dict__)\n' 120 | 121 | if import_from is None: 122 | if asname is None: 123 | if name != module_name: 124 | result += f'{name} = {module_name}\n' 125 | else: 126 | result += f'{asname} = {module_name}\n' 127 | else: 128 | if asname is None: 129 | if name != import_from + '.' + name: 130 | result += f'{name} = {import_from}.{name}\n' 131 | else: 132 | result += f'{asname} = {import_from}.{name}\n' 133 | 134 | return result + '\n' 135 | 136 | 137 | def main() -> None: 138 | parser = argparse.ArgumentParser() 139 | parser.add_argument('src', help='Source code') 140 | parser.add_argument('-o', '--output', help='Single combined code') 141 | args = parser.parse_args() 142 | 143 | with open(args.src) as f: 144 | lines = f.readlines() 145 | imports = iter_child_nodes(ast.parse(''.join(lines))) 146 | 147 | importer = ModuleImporter() 148 | result = 'import types\n\n' 149 | import_lines = [] 150 | for import_info in imports: 151 | result += importer.import_module( 152 | import_info.import_from, cast(str, import_info.name), 153 | import_info.asname) 154 | for line in range(import_info.lineno - 1, import_info.end_lineno): 155 | import_lines.append(line) 156 | 157 | for lineno, line_str in enumerate(lines): 158 | if lineno not in import_lines: 159 | continue 160 | lines[lineno] = '# ' + line_str # TODO(not): indent 161 | result += ''.join(lines) 162 | 163 | if args.output: 164 | with open(args.output, 'w') as f: 165 | f.write(result) 166 | else: 167 | print(result, end='') 168 | 169 | 170 | if __name__ == '__main__': 171 | main() 172 | -------------------------------------------------------------------------------- /atcoder/_bit.py: -------------------------------------------------------------------------------- 1 | def _ceil_pow2(n: int) -> int: 2 | x = 0 3 | while (1 << x) < n: 4 | x += 1 5 | 6 | return x 7 | 8 | 9 | def _bsf(n: int) -> int: 10 | x = 0 11 | while n % 2 == 0: 12 | x += 1 13 | n //= 2 14 | 15 | return x 16 | -------------------------------------------------------------------------------- /atcoder/_math.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | 4 | def _is_prime(n: int) -> bool: 5 | ''' 6 | Reference: 7 | M. Forisek and J. Jancina, 8 | Fast Primality Testing for Integers That Fit into a Machine Word 9 | ''' 10 | 11 | if n <= 1: 12 | return False 13 | if n == 2 or n == 7 or n == 61: 14 | return True 15 | if n % 2 == 0: 16 | return False 17 | 18 | d = n - 1 19 | while d % 2 == 0: 20 | d //= 2 21 | 22 | for a in (2, 7, 61): 23 | t = d 24 | y = pow(a, t, n) 25 | while t != n - 1 and y != 1 and y != n - 1: 26 | y = y * y % n 27 | t <<= 1 28 | if y != n - 1 and t % 2 == 0: 29 | return False 30 | return True 31 | 32 | 33 | def _inv_gcd(a: int, b: int) -> typing.Tuple[int, int]: 34 | a %= b 35 | if a == 0: 36 | return (b, 0) 37 | 38 | # Contracts: 39 | # [1] s - m0 * a = 0 (mod b) 40 | # [2] t - m1 * a = 0 (mod b) 41 | # [3] s * |m1| + t * |m0| <= b 42 | s = b 43 | t = a 44 | m0 = 0 45 | m1 = 1 46 | 47 | while t: 48 | u = s // t 49 | s -= t * u 50 | m0 -= m1 * u # |m1 * u| <= |m1| * s <= b 51 | 52 | # [3]: 53 | # (s - t * u) * |m1| + t * |m0 - m1 * u| 54 | # <= s * |m1| - t * u * |m1| + t * (|m0| + |m1| * u) 55 | # = s * |m1| + t * |m0| <= b 56 | 57 | s, t = t, s 58 | m0, m1 = m1, m0 59 | 60 | # by [3]: |m0| <= b/g 61 | # by g != b: |m0| < b/g 62 | if m0 < 0: 63 | m0 += b // s 64 | 65 | return (s, m0) 66 | 67 | 68 | def _primitive_root(m: int) -> int: 69 | if m == 2: 70 | return 1 71 | if m == 167772161: 72 | return 3 73 | if m == 469762049: 74 | return 3 75 | if m == 754974721: 76 | return 11 77 | if m == 998244353: 78 | return 3 79 | 80 | divs = [2] + [0] * 19 81 | cnt = 1 82 | x = (m - 1) // 2 83 | while x % 2 == 0: 84 | x //= 2 85 | 86 | i = 3 87 | while i * i <= x: 88 | if x % i == 0: 89 | divs[cnt] = i 90 | cnt += 1 91 | while x % i == 0: 92 | x //= i 93 | i += 2 94 | 95 | if x > 1: 96 | divs[cnt] = x 97 | cnt += 1 98 | 99 | g = 2 100 | while True: 101 | for i in range(cnt): 102 | if pow(g, (m - 1) // divs[i], m) == 1: 103 | break 104 | else: 105 | return g 106 | g += 1 107 | -------------------------------------------------------------------------------- /atcoder/_scc.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import typing 3 | 4 | 5 | class CSR: 6 | def __init__( 7 | self, n: int, edges: typing.List[typing.Tuple[int, int]]) -> None: 8 | self.start = [0] * (n + 1) 9 | self.elist = [0] * len(edges) 10 | 11 | for e in edges: 12 | self.start[e[0] + 1] += 1 13 | 14 | for i in range(1, n + 1): 15 | self.start[i] += self.start[i - 1] 16 | 17 | counter = self.start.copy() 18 | for e in edges: 19 | self.elist[counter[e[0]]] = e[1] 20 | counter[e[0]] += 1 21 | 22 | 23 | class SCCGraph: 24 | ''' 25 | Reference: 26 | R. Tarjan, 27 | Depth-First Search and Linear Graph Algorithms 28 | ''' 29 | 30 | def __init__(self, n: int) -> None: 31 | self._n = n 32 | self._edges: typing.List[typing.Tuple[int, int]] = [] 33 | 34 | def num_vertices(self) -> int: 35 | return self._n 36 | 37 | def add_edge(self, from_vertex: int, to_vertex: int) -> None: 38 | self._edges.append((from_vertex, to_vertex)) 39 | 40 | def scc_ids(self) -> typing.Tuple[int, typing.List[int]]: 41 | g = CSR(self._n, self._edges) 42 | now_ord = 0 43 | group_num = 0 44 | visited = [] 45 | low = [0] * self._n 46 | order = [-1] * self._n 47 | ids = [0] * self._n 48 | 49 | sys.setrecursionlimit(max(self._n + 1000, sys.getrecursionlimit())) 50 | 51 | def dfs(v: int) -> None: 52 | nonlocal now_ord 53 | nonlocal group_num 54 | nonlocal visited 55 | nonlocal low 56 | nonlocal order 57 | nonlocal ids 58 | 59 | low[v] = now_ord 60 | order[v] = now_ord 61 | now_ord += 1 62 | visited.append(v) 63 | for i in range(g.start[v], g.start[v + 1]): 64 | to = g.elist[i] 65 | if order[to] == -1: 66 | dfs(to) 67 | low[v] = min(low[v], low[to]) 68 | else: 69 | low[v] = min(low[v], order[to]) 70 | 71 | if low[v] == order[v]: 72 | while True: 73 | u = visited[-1] 74 | visited.pop() 75 | order[u] = self._n 76 | ids[u] = group_num 77 | if u == v: 78 | break 79 | group_num += 1 80 | 81 | for i in range(self._n): 82 | if order[i] == -1: 83 | dfs(i) 84 | 85 | for i in range(self._n): 86 | ids[i] = group_num - 1 - ids[i] 87 | 88 | return group_num, ids 89 | 90 | def scc(self) -> typing.List[typing.List[int]]: 91 | ids = self.scc_ids() 92 | group_num = ids[0] 93 | counts = [0] * group_num 94 | for x in ids[1]: 95 | counts[x] += 1 96 | groups: typing.List[typing.List[int]] = [[] for _ in range(group_num)] 97 | for i in range(self._n): 98 | groups[ids[1][i]].append(i) 99 | 100 | return groups 101 | -------------------------------------------------------------------------------- /atcoder/convolution.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | import atcoder._bit 4 | import atcoder._math 5 | from atcoder.modint import ModContext, Modint 6 | 7 | 8 | _sum_e = {} # _sum_e[i] = ies[0] * ... * ies[i - 1] * es[i] 9 | 10 | 11 | def _butterfly(a: typing.List[Modint]) -> None: 12 | g = atcoder._math._primitive_root(a[0].mod()) 13 | n = len(a) 14 | h = atcoder._bit._ceil_pow2(n) 15 | 16 | if a[0].mod() not in _sum_e: 17 | es = [Modint(0)] * 30 # es[i]^(2^(2+i)) == 1 18 | ies = [Modint(0)] * 30 19 | cnt2 = atcoder._bit._bsf(a[0].mod() - 1) 20 | e = Modint(g) ** ((a[0].mod() - 1) >> cnt2) 21 | ie = e.inv() 22 | for i in range(cnt2, 1, -1): 23 | # e^(2^i) == 1 24 | es[i - 2] = e 25 | ies[i - 2] = ie 26 | e = e * e 27 | ie = ie * ie 28 | sum_e = [Modint(0)] * 30 29 | now = Modint(1) 30 | for i in range(cnt2 - 2): 31 | sum_e[i] = es[i] * now 32 | now *= ies[i] 33 | _sum_e[a[0].mod()] = sum_e 34 | else: 35 | sum_e = _sum_e[a[0].mod()] 36 | 37 | for ph in range(1, h + 1): 38 | w = 1 << (ph - 1) 39 | p = 1 << (h - ph) 40 | now = Modint(1) 41 | for s in range(w): 42 | offset = s << (h - ph + 1) 43 | for i in range(p): 44 | left = a[i + offset] 45 | right = a[i + offset + p] * now 46 | a[i + offset] = left + right 47 | a[i + offset + p] = left - right 48 | now *= sum_e[atcoder._bit._bsf(~s)] 49 | 50 | 51 | _sum_ie = {} # _sum_ie[i] = es[0] * ... * es[i - 1] * ies[i] 52 | 53 | 54 | def _butterfly_inv(a: typing.List[Modint]) -> None: 55 | g = atcoder._math._primitive_root(a[0].mod()) 56 | n = len(a) 57 | h = atcoder._bit._ceil_pow2(n) 58 | 59 | if a[0].mod() not in _sum_ie: 60 | es = [Modint(0)] * 30 # es[i]^(2^(2+i)) == 1 61 | ies = [Modint(0)] * 30 62 | cnt2 = atcoder._bit._bsf(a[0].mod() - 1) 63 | e = Modint(g) ** ((a[0].mod() - 1) >> cnt2) 64 | ie = e.inv() 65 | for i in range(cnt2, 1, -1): 66 | # e^(2^i) == 1 67 | es[i - 2] = e 68 | ies[i - 2] = ie 69 | e = e * e 70 | ie = ie * ie 71 | sum_ie = [Modint(0)] * 30 72 | now = Modint(1) 73 | for i in range(cnt2 - 2): 74 | sum_ie[i] = ies[i] * now 75 | now *= es[i] 76 | _sum_ie[a[0].mod()] = sum_ie 77 | else: 78 | sum_ie = _sum_ie[a[0].mod()] 79 | 80 | for ph in range(h, 0, -1): 81 | w = 1 << (ph - 1) 82 | p = 1 << (h - ph) 83 | inow = Modint(1) 84 | for s in range(w): 85 | offset = s << (h - ph + 1) 86 | for i in range(p): 87 | left = a[i + offset] 88 | right = a[i + offset + p] 89 | a[i + offset] = left + right 90 | a[i + offset + p] = Modint( 91 | (a[0].mod() + left.val() - right.val()) * inow.val()) 92 | inow *= sum_ie[atcoder._bit._bsf(~s)] 93 | 94 | 95 | def convolution_mod(a: typing.List[Modint], 96 | b: typing.List[Modint]) -> typing.List[Modint]: 97 | n = len(a) 98 | m = len(b) 99 | 100 | if n == 0 or m == 0: 101 | return [] 102 | 103 | if min(n, m) <= 60: 104 | if n < m: 105 | n, m = m, n 106 | a, b = b, a 107 | ans = [Modint(0) for _ in range(n + m - 1)] 108 | for i in range(n): 109 | for j in range(m): 110 | ans[i + j] += a[i] * b[j] 111 | return ans 112 | 113 | z = 1 << atcoder._bit._ceil_pow2(n + m - 1) 114 | 115 | while len(a) < z: 116 | a.append(Modint(0)) 117 | _butterfly(a) 118 | 119 | while len(b) < z: 120 | b.append(Modint(0)) 121 | _butterfly(b) 122 | 123 | for i in range(z): 124 | a[i] *= b[i] 125 | _butterfly_inv(a) 126 | a = a[:n + m - 1] 127 | 128 | iz = Modint(z).inv() 129 | for i in range(n + m - 1): 130 | a[i] *= iz 131 | 132 | return a 133 | 134 | 135 | def convolution(mod: int, a: typing.List[typing.Any], 136 | b: typing.List[typing.Any]) -> typing.List[typing.Any]: 137 | n = len(a) 138 | m = len(b) 139 | 140 | if n == 0 or m == 0: 141 | return [] 142 | 143 | with ModContext(mod): 144 | a2 = list(map(Modint, a)) 145 | b2 = list(map(Modint, b)) 146 | 147 | return list(map(lambda c: c.val(), convolution_mod(a2, b2))) 148 | 149 | 150 | def convolution_int( 151 | a: typing.List[int], b: typing.List[int]) -> typing.List[int]: 152 | n = len(a) 153 | m = len(b) 154 | 155 | if n == 0 or m == 0: 156 | return [] 157 | 158 | mod1 = 754974721 # 2^24 159 | mod2 = 167772161 # 2^25 160 | mod3 = 469762049 # 2^26 161 | m2m3 = mod2 * mod3 162 | m1m3 = mod1 * mod3 163 | m1m2 = mod1 * mod2 164 | m1m2m3 = mod1 * mod2 * mod3 165 | 166 | i1 = atcoder._math._inv_gcd(mod2 * mod3, mod1)[1] 167 | i2 = atcoder._math._inv_gcd(mod1 * mod3, mod2)[1] 168 | i3 = atcoder._math._inv_gcd(mod1 * mod2, mod3)[1] 169 | 170 | c1 = convolution(mod1, a, b) 171 | c2 = convolution(mod2, a, b) 172 | c3 = convolution(mod3, a, b) 173 | 174 | c = [0] * (n + m - 1) 175 | for i in range(n + m - 1): 176 | c[i] += (c1[i] * i1) % mod1 * m2m3 177 | c[i] += (c2[i] * i2) % mod2 * m1m3 178 | c[i] += (c3[i] * i3) % mod3 * m1m2 179 | c[i] %= m1m2m3 180 | 181 | return c 182 | -------------------------------------------------------------------------------- /atcoder/dsu.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | 4 | class DSU: 5 | ''' 6 | Implement (union by size) + (path halving) 7 | 8 | Reference: 9 | Zvi Galil and Giuseppe F. Italiano, 10 | Data structures and algorithms for disjoint set union problems 11 | ''' 12 | 13 | def __init__(self, n: int = 0) -> None: 14 | self._n = n 15 | self.parent_or_size = [-1] * n 16 | 17 | def merge(self, a: int, b: int) -> int: 18 | assert 0 <= a < self._n 19 | assert 0 <= b < self._n 20 | 21 | x = self.leader(a) 22 | y = self.leader(b) 23 | 24 | if x == y: 25 | return x 26 | 27 | if -self.parent_or_size[x] < -self.parent_or_size[y]: 28 | x, y = y, x 29 | 30 | self.parent_or_size[x] += self.parent_or_size[y] 31 | self.parent_or_size[y] = x 32 | 33 | return x 34 | 35 | def same(self, a: int, b: int) -> bool: 36 | assert 0 <= a < self._n 37 | assert 0 <= b < self._n 38 | 39 | return self.leader(a) == self.leader(b) 40 | 41 | def leader(self, a: int) -> int: 42 | assert 0 <= a < self._n 43 | 44 | parent = self.parent_or_size[a] 45 | while parent >= 0: 46 | if self.parent_or_size[parent] < 0: 47 | return parent 48 | self.parent_or_size[a], a, parent = ( 49 | self.parent_or_size[parent], 50 | self.parent_or_size[parent], 51 | self.parent_or_size[self.parent_or_size[parent]] 52 | ) 53 | 54 | return a 55 | 56 | def size(self, a: int) -> int: 57 | assert 0 <= a < self._n 58 | 59 | return -self.parent_or_size[self.leader(a)] 60 | 61 | def groups(self) -> typing.List[typing.List[int]]: 62 | leader_buf = [self.leader(i) for i in range(self._n)] 63 | 64 | result: typing.List[typing.List[int]] = [[] for _ in range(self._n)] 65 | for i in range(self._n): 66 | result[leader_buf[i]].append(i) 67 | 68 | return list(filter(lambda r: r, result)) 69 | -------------------------------------------------------------------------------- /atcoder/fenwicktree.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | 4 | class FenwickTree: 5 | '''Reference: https://en.wikipedia.org/wiki/Fenwick_tree''' 6 | 7 | def __init__(self, n: int = 0) -> None: 8 | self._n = n 9 | self.data = [0] * n 10 | 11 | def add(self, p: int, x: typing.Any) -> None: 12 | assert 0 <= p < self._n 13 | 14 | p += 1 15 | while p <= self._n: 16 | self.data[p - 1] += x 17 | p += p & -p 18 | 19 | def sum(self, left: int, right: int) -> typing.Any: 20 | assert 0 <= left <= right <= self._n 21 | 22 | return self._sum(right) - self._sum(left) 23 | 24 | def _sum(self, r: int) -> typing.Any: 25 | s = 0 26 | while r > 0: 27 | s += self.data[r - 1] 28 | r -= r & -r 29 | 30 | return s 31 | -------------------------------------------------------------------------------- /atcoder/lazysegtree.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | import atcoder._bit 4 | 5 | 6 | class LazySegTree: 7 | def __init__( 8 | self, 9 | op: typing.Callable[[typing.Any, typing.Any], typing.Any], 10 | e: typing.Any, 11 | mapping: typing.Callable[[typing.Any, typing.Any], typing.Any], 12 | composition: typing.Callable[[typing.Any, typing.Any], typing.Any], 13 | id_: typing.Any, 14 | v: typing.Union[int, typing.List[typing.Any]]) -> None: 15 | self._op = op 16 | self._e = e 17 | self._mapping = mapping 18 | self._composition = composition 19 | self._id = id_ 20 | 21 | if isinstance(v, int): 22 | v = [e] * v 23 | 24 | self._n = len(v) 25 | self._log = atcoder._bit._ceil_pow2(self._n) 26 | self._size = 1 << self._log 27 | self._d = [e] * (2 * self._size) 28 | self._lz = [self._id] * self._size 29 | for i in range(self._n): 30 | self._d[self._size + i] = v[i] 31 | for i in range(self._size - 1, 0, -1): 32 | self._update(i) 33 | 34 | def set(self, p: int, x: typing.Any) -> None: 35 | assert 0 <= p < self._n 36 | 37 | p += self._size 38 | for i in range(self._log, 0, -1): 39 | self._push(p >> i) 40 | self._d[p] = x 41 | for i in range(1, self._log + 1): 42 | self._update(p >> i) 43 | 44 | def get(self, p: int) -> typing.Any: 45 | assert 0 <= p < self._n 46 | 47 | p += self._size 48 | for i in range(self._log, 0, -1): 49 | self._push(p >> i) 50 | return self._d[p] 51 | 52 | def prod(self, left: int, right: int) -> typing.Any: 53 | assert 0 <= left <= right <= self._n 54 | 55 | if left == right: 56 | return self._e 57 | 58 | left += self._size 59 | right += self._size 60 | 61 | for i in range(self._log, 0, -1): 62 | if ((left >> i) << i) != left: 63 | self._push(left >> i) 64 | if ((right >> i) << i) != right: 65 | self._push((right - 1) >> i) 66 | 67 | sml = self._e 68 | smr = self._e 69 | while left < right: 70 | if left & 1: 71 | sml = self._op(sml, self._d[left]) 72 | left += 1 73 | if right & 1: 74 | right -= 1 75 | smr = self._op(self._d[right], smr) 76 | left >>= 1 77 | right >>= 1 78 | 79 | return self._op(sml, smr) 80 | 81 | def all_prod(self) -> typing.Any: 82 | return self._d[1] 83 | 84 | def apply(self, left: int, right: typing.Optional[int] = None, 85 | f: typing.Optional[typing.Any] = None) -> None: 86 | assert f is not None 87 | 88 | if right is None: 89 | p = left 90 | assert 0 <= left < self._n 91 | 92 | p += self._size 93 | for i in range(self._log, 0, -1): 94 | self._push(p >> i) 95 | self._d[p] = self._mapping(f, self._d[p]) 96 | for i in range(1, self._log + 1): 97 | self._update(p >> i) 98 | else: 99 | assert 0 <= left <= right <= self._n 100 | if left == right: 101 | return 102 | 103 | left += self._size 104 | right += self._size 105 | 106 | for i in range(self._log, 0, -1): 107 | if ((left >> i) << i) != left: 108 | self._push(left >> i) 109 | if ((right >> i) << i) != right: 110 | self._push((right - 1) >> i) 111 | 112 | l2 = left 113 | r2 = right 114 | while left < right: 115 | if left & 1: 116 | self._all_apply(left, f) 117 | left += 1 118 | if right & 1: 119 | right -= 1 120 | self._all_apply(right, f) 121 | left >>= 1 122 | right >>= 1 123 | left = l2 124 | right = r2 125 | 126 | for i in range(1, self._log + 1): 127 | if ((left >> i) << i) != left: 128 | self._update(left >> i) 129 | if ((right >> i) << i) != right: 130 | self._update((right - 1) >> i) 131 | 132 | def max_right( 133 | self, left: int, g: typing.Callable[[typing.Any], bool]) -> int: 134 | assert 0 <= left <= self._n 135 | assert g(self._e) 136 | 137 | if left == self._n: 138 | return self._n 139 | 140 | left += self._size 141 | for i in range(self._log, 0, -1): 142 | self._push(left >> i) 143 | 144 | sm = self._e 145 | first = True 146 | while first or (left & -left) != left: 147 | first = False 148 | while left % 2 == 0: 149 | left >>= 1 150 | if not g(self._op(sm, self._d[left])): 151 | while left < self._size: 152 | self._push(left) 153 | left *= 2 154 | if g(self._op(sm, self._d[left])): 155 | sm = self._op(sm, self._d[left]) 156 | left += 1 157 | return left - self._size 158 | sm = self._op(sm, self._d[left]) 159 | left += 1 160 | 161 | return self._n 162 | 163 | def min_left(self, right: int, g: typing.Any) -> int: 164 | assert 0 <= right <= self._n 165 | assert g(self._e) 166 | 167 | if right == 0: 168 | return 0 169 | 170 | right += self._size 171 | for i in range(self._log, 0, -1): 172 | self._push((right - 1) >> i) 173 | 174 | sm = self._e 175 | first = True 176 | while first or (right & -right) != right: 177 | first = False 178 | right -= 1 179 | while right > 1 and right % 2: 180 | right >>= 1 181 | if not g(self._op(self._d[right], sm)): 182 | while right < self._size: 183 | self._push(right) 184 | right = 2 * right + 1 185 | if g(self._op(self._d[right], sm)): 186 | sm = self._op(self._d[right], sm) 187 | right -= 1 188 | return right + 1 - self._size 189 | sm = self._op(self._d[right], sm) 190 | 191 | return 0 192 | 193 | def _update(self, k: int) -> None: 194 | self._d[k] = self._op(self._d[2 * k], self._d[2 * k + 1]) 195 | 196 | def _all_apply(self, k: int, f: typing.Any) -> None: 197 | self._d[k] = self._mapping(f, self._d[k]) 198 | if k < self._size: 199 | self._lz[k] = self._composition(f, self._lz[k]) 200 | 201 | def _push(self, k: int) -> None: 202 | self._all_apply(2 * k, self._lz[k]) 203 | self._all_apply(2 * k + 1, self._lz[k]) 204 | self._lz[k] = self._id 205 | -------------------------------------------------------------------------------- /atcoder/math.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | import atcoder._math 4 | 5 | def pow_mod(x: int, n: int, m: int) -> int: 6 | return pow(x, n, m) 7 | 8 | 9 | def inv_mod(x: int, m: int) -> int: 10 | assert 1 <= m 11 | 12 | z = atcoder._math._inv_gcd(x, m) 13 | 14 | assert z[0] == 1 15 | 16 | return z[1] 17 | 18 | 19 | def crt(r: typing.List[int], m: typing.List[int]) -> typing.Tuple[int, int]: 20 | assert len(r) == len(m) 21 | 22 | # Contracts: 0 <= r0 < m0 23 | r0 = 0 24 | m0 = 1 25 | for r1, m1 in zip(r, m): 26 | assert 1 <= m1 27 | r1 %= m1 28 | if m0 < m1: 29 | r0, r1 = r1, r0 30 | m0, m1 = m1, m0 31 | if m0 % m1 == 0: 32 | if r0 % m1 != r1: 33 | return (0, 0) 34 | continue 35 | 36 | # assume: m0 > m1, lcm(m0, m1) >= 2 * max(m0, m1) 37 | 38 | ''' 39 | (r0, m0), (r1, m1) -> (r2, m2 = lcm(m0, m1)); 40 | r2 % m0 = r0 41 | r2 % m1 = r1 42 | -> (r0 + x*m0) % m1 = r1 43 | -> x*u0*g % (u1*g) = (r1 - r0) (u0*g = m0, u1*g = m1) 44 | -> x = (r1 - r0) / g * inv(u0) (mod u1) 45 | ''' 46 | 47 | # im = inv(u0) (mod u1) (0 <= im < u1) 48 | g, im = atcoder._math._inv_gcd(m0, m1) 49 | 50 | u1 = m1 // g 51 | # |r1 - r0| < (m0 + m1) <= lcm(m0, m1) 52 | if (r1 - r0) % g: 53 | return (0, 0) 54 | 55 | # u1 * u1 <= m1 * m1 / g / g <= m0 * m1 / g = lcm(m0, m1) 56 | x = (r1 - r0) // g % u1 * im % u1 57 | 58 | ''' 59 | |r0| + |m0 * x| 60 | < m0 + m0 * (u1 - 1) 61 | = m0 + m0 * m1 / g - m0 62 | = lcm(m0, m1) 63 | ''' 64 | 65 | r0 += x * m0 66 | m0 *= u1 # -> lcm(m0, m1) 67 | if r0 < 0: 68 | r0 += m0 69 | 70 | return (r0, m0) 71 | 72 | 73 | def floor_sum(n: int, m: int, a: int, b: int) -> int: 74 | assert 1 <= n 75 | assert 1 <= m 76 | 77 | ans = 0 78 | 79 | if a >= m: 80 | ans += (n - 1) * n * (a // m) // 2 81 | a %= m 82 | 83 | if b >= m: 84 | ans += n * (b // m) 85 | b %= m 86 | 87 | y_max = (a * n + b) // m 88 | x_max = y_max * m - b 89 | 90 | if y_max == 0: 91 | return ans 92 | 93 | ans += (n - (x_max + a - 1) // a) * y_max 94 | ans += floor_sum(y_max, a, m, (a - x_max % a) % a) 95 | 96 | return ans 97 | -------------------------------------------------------------------------------- /atcoder/maxflow.py: -------------------------------------------------------------------------------- 1 | from typing import NamedTuple, Optional, List, cast 2 | 3 | 4 | class MFGraph: 5 | class Edge(NamedTuple): 6 | src: int 7 | dst: int 8 | cap: int 9 | flow: int 10 | 11 | class _Edge: 12 | def __init__(self, dst: int, cap: int) -> None: 13 | self.dst = dst 14 | self.cap = cap 15 | self.rev: Optional[MFGraph._Edge] = None 16 | 17 | def __init__(self, n: int) -> None: 18 | self._n = n 19 | self._g: List[List[MFGraph._Edge]] = [[] for _ in range(n)] 20 | self._edges: List[MFGraph._Edge] = [] 21 | 22 | def add_edge(self, src: int, dst: int, cap: int) -> int: 23 | assert 0 <= src < self._n 24 | assert 0 <= dst < self._n 25 | assert 0 <= cap 26 | m = len(self._edges) 27 | e = MFGraph._Edge(dst, cap) 28 | re = MFGraph._Edge(src, 0) 29 | e.rev = re 30 | re.rev = e 31 | self._g[src].append(e) 32 | self._g[dst].append(re) 33 | self._edges.append(e) 34 | return m 35 | 36 | def get_edge(self, i: int) -> Edge: 37 | assert 0 <= i < len(self._edges) 38 | e = self._edges[i] 39 | re = cast(MFGraph._Edge, e.rev) 40 | return MFGraph.Edge( 41 | re.dst, 42 | e.dst, 43 | e.cap + re.cap, 44 | re.cap 45 | ) 46 | 47 | def edges(self) -> List[Edge]: 48 | return [self.get_edge(i) for i in range(len(self._edges))] 49 | 50 | def change_edge(self, i: int, new_cap: int, new_flow: int) -> None: 51 | assert 0 <= i < len(self._edges) 52 | assert 0 <= new_flow <= new_cap 53 | e = self._edges[i] 54 | e.cap = new_cap - new_flow 55 | assert e.rev is not None 56 | e.rev.cap = new_flow 57 | 58 | def flow(self, s: int, t: int, flow_limit: Optional[int] = None) -> int: 59 | assert 0 <= s < self._n 60 | assert 0 <= t < self._n 61 | assert s != t 62 | if flow_limit is None: 63 | flow_limit = cast(int, sum(e.cap for e in self._g[s])) 64 | 65 | current_edge = [0] * self._n 66 | level = [0] * self._n 67 | 68 | def fill(arr: List[int], value: int) -> None: 69 | for i in range(len(arr)): 70 | arr[i] = value 71 | 72 | def bfs() -> bool: 73 | fill(level, self._n) 74 | queue = [] 75 | q_front = 0 76 | queue.append(s) 77 | level[s] = 0 78 | while q_front < len(queue): 79 | v = queue[q_front] 80 | q_front += 1 81 | next_level = level[v] + 1 82 | for e in self._g[v]: 83 | if e.cap == 0 or level[e.dst] <= next_level: 84 | continue 85 | level[e.dst] = next_level 86 | if e.dst == t: 87 | return True 88 | queue.append(e.dst) 89 | return False 90 | 91 | def dfs(lim: int) -> int: 92 | stack = [] 93 | edge_stack: List[MFGraph._Edge] = [] 94 | stack.append(t) 95 | while stack: 96 | v = stack[-1] 97 | if v == s: 98 | flow = min(lim, min(e.cap for e in edge_stack)) 99 | for e in edge_stack: 100 | e.cap -= flow 101 | assert e.rev is not None 102 | e.rev.cap += flow 103 | return flow 104 | next_level = level[v] - 1 105 | while current_edge[v] < len(self._g[v]): 106 | e = self._g[v][current_edge[v]] 107 | re = cast(MFGraph._Edge, e.rev) 108 | if level[e.dst] != next_level or re.cap == 0: 109 | current_edge[v] += 1 110 | continue 111 | stack.append(e.dst) 112 | edge_stack.append(re) 113 | break 114 | else: 115 | stack.pop() 116 | if edge_stack: 117 | edge_stack.pop() 118 | level[v] = self._n 119 | return 0 120 | 121 | flow = 0 122 | while flow < flow_limit: 123 | if not bfs(): 124 | break 125 | fill(current_edge, 0) 126 | while flow < flow_limit: 127 | f = dfs(flow_limit - flow) 128 | flow += f 129 | if f == 0: 130 | break 131 | return flow 132 | 133 | def min_cut(self, s: int) -> List[bool]: 134 | visited = [False] * self._n 135 | stack = [s] 136 | visited[s] = True 137 | while stack: 138 | v = stack.pop() 139 | for e in self._g[v]: 140 | if e.cap > 0 and not visited[e.dst]: 141 | visited[e.dst] = True 142 | stack.append(e.dst) 143 | return visited 144 | -------------------------------------------------------------------------------- /atcoder/mincostflow.py: -------------------------------------------------------------------------------- 1 | from typing import NamedTuple, Optional, List, Tuple, cast 2 | from heapq import heappush, heappop 3 | 4 | 5 | class MCFGraph: 6 | class Edge(NamedTuple): 7 | src: int 8 | dst: int 9 | cap: int 10 | flow: int 11 | cost: int 12 | 13 | class _Edge: 14 | def __init__(self, dst: int, cap: int, cost: int) -> None: 15 | self.dst = dst 16 | self.cap = cap 17 | self.cost = cost 18 | self.rev: Optional[MCFGraph._Edge] = None 19 | 20 | def __init__(self, n: int) -> None: 21 | self._n = n 22 | self._g: List[List[MCFGraph._Edge]] = [[] for _ in range(n)] 23 | self._edges: List[MCFGraph._Edge] = [] 24 | 25 | def add_edge(self, src: int, dst: int, cap: int, cost: int) -> int: 26 | assert 0 <= src < self._n 27 | assert 0 <= dst < self._n 28 | assert 0 <= cap 29 | m = len(self._edges) 30 | e = MCFGraph._Edge(dst, cap, cost) 31 | re = MCFGraph._Edge(src, 0, -cost) 32 | e.rev = re 33 | re.rev = e 34 | self._g[src].append(e) 35 | self._g[dst].append(re) 36 | self._edges.append(e) 37 | return m 38 | 39 | def get_edge(self, i: int) -> Edge: 40 | assert 0 <= i < len(self._edges) 41 | e = self._edges[i] 42 | re = cast(MCFGraph._Edge, e.rev) 43 | return MCFGraph.Edge( 44 | re.dst, 45 | e.dst, 46 | e.cap + re.cap, 47 | re.cap, 48 | e.cost 49 | ) 50 | 51 | def edges(self) -> List[Edge]: 52 | return [self.get_edge(i) for i in range(len(self._edges))] 53 | 54 | def flow(self, s: int, t: int, 55 | flow_limit: Optional[int] = None) -> Tuple[int, int]: 56 | return self.slope(s, t, flow_limit)[-1] 57 | 58 | def slope(self, s: int, t: int, 59 | flow_limit: Optional[int] = None) -> List[Tuple[int, int]]: 60 | assert 0 <= s < self._n 61 | assert 0 <= t < self._n 62 | assert s != t 63 | if flow_limit is None: 64 | flow_limit = cast(int, sum(e.cap for e in self._g[s])) 65 | 66 | dual = [0] * self._n 67 | prev: List[Optional[Tuple[int, MCFGraph._Edge]]] = [None] * self._n 68 | 69 | def refine_dual() -> bool: 70 | pq = [(0, s)] 71 | visited = [False] * self._n 72 | dist: List[Optional[int]] = [None] * self._n 73 | dist[s] = 0 74 | while pq: 75 | dist_v, v = heappop(pq) 76 | if visited[v]: 77 | continue 78 | visited[v] = True 79 | if v == t: 80 | break 81 | dual_v = dual[v] 82 | for e in self._g[v]: 83 | w = e.dst 84 | if visited[w] or e.cap == 0: 85 | continue 86 | reduced_cost = e.cost - dual[w] + dual_v 87 | new_dist = dist_v + reduced_cost 88 | dist_w = dist[w] 89 | if dist_w is None or new_dist < dist_w: 90 | dist[w] = new_dist 91 | prev[w] = v, e 92 | heappush(pq, (new_dist, w)) 93 | else: 94 | return False 95 | dist_t = dist[t] 96 | for v in range(self._n): 97 | if visited[v]: 98 | dual[v] -= cast(int, dist_t) - cast(int, dist[v]) 99 | return True 100 | 101 | flow = 0 102 | cost = 0 103 | prev_cost_per_flow: Optional[int] = None 104 | result = [(flow, cost)] 105 | while flow < flow_limit: 106 | if not refine_dual(): 107 | break 108 | f = flow_limit - flow 109 | v = t 110 | while prev[v] is not None: 111 | u, e = cast(Tuple[int, MCFGraph._Edge], prev[v]) 112 | f = min(f, e.cap) 113 | v = u 114 | v = t 115 | while prev[v] is not None: 116 | u, e = cast(Tuple[int, MCFGraph._Edge], prev[v]) 117 | e.cap -= f 118 | assert e.rev is not None 119 | e.rev.cap += f 120 | v = u 121 | c = -dual[s] 122 | flow += f 123 | cost += f * c 124 | if c == prev_cost_per_flow: 125 | result.pop() 126 | result.append((flow, cost)) 127 | prev_cost_per_flow = c 128 | return result 129 | -------------------------------------------------------------------------------- /atcoder/modint.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | import atcoder._math 4 | 5 | 6 | class ModContext: 7 | context: typing.List[int] = [] 8 | 9 | def __init__(self, mod: int) -> None: 10 | assert 1 <= mod 11 | 12 | self.mod = mod 13 | 14 | def __enter__(self) -> None: 15 | self.context.append(self.mod) 16 | 17 | def __exit__(self, exc_type: typing.Any, exc_value: typing.Any, 18 | traceback: typing.Any) -> None: 19 | self.context.pop() 20 | 21 | @classmethod 22 | def get_mod(cls) -> int: 23 | return cls.context[-1] 24 | 25 | 26 | class Modint: 27 | def __init__(self, v: int = 0) -> None: 28 | self._mod = ModContext.get_mod() 29 | if v == 0: 30 | self._v = 0 31 | else: 32 | self._v = v % self._mod 33 | 34 | def mod(self) -> int: 35 | return self._mod 36 | 37 | def val(self) -> int: 38 | return self._v 39 | 40 | def __iadd__(self, rhs: typing.Union['Modint', int]) -> 'Modint': 41 | if isinstance(rhs, Modint): 42 | self._v += rhs._v 43 | else: 44 | self._v += rhs 45 | if self._v >= self._mod: 46 | self._v -= self._mod 47 | return self 48 | 49 | def __isub__(self, rhs: typing.Union['Modint', int]) -> 'Modint': 50 | if isinstance(rhs, Modint): 51 | self._v -= rhs._v 52 | else: 53 | self._v -= rhs 54 | if self._v < 0: 55 | self._v += self._mod 56 | return self 57 | 58 | def __imul__(self, rhs: typing.Union['Modint', int]) -> 'Modint': 59 | if isinstance(rhs, Modint): 60 | self._v = self._v * rhs._v % self._mod 61 | else: 62 | self._v = self._v * rhs % self._mod 63 | return self 64 | 65 | def __ifloordiv__(self, rhs: typing.Union['Modint', int]) -> 'Modint': 66 | if isinstance(rhs, Modint): 67 | inv = rhs.inv()._v 68 | else: 69 | inv = atcoder._math._inv_gcd(rhs, self._mod)[1] 70 | self._v = self._v * inv % self._mod 71 | return self 72 | 73 | def __pos__(self) -> 'Modint': 74 | return self 75 | 76 | def __neg__(self) -> 'Modint': 77 | return Modint() - self 78 | 79 | def __pow__(self, n: int) -> 'Modint': 80 | assert 0 <= n 81 | 82 | return Modint(pow(self._v, n, self._mod)) 83 | 84 | def inv(self) -> 'Modint': 85 | eg = atcoder._math._inv_gcd(self._v, self._mod) 86 | 87 | assert eg[0] == 1 88 | 89 | return Modint(eg[1]) 90 | 91 | def __add__(self, rhs: typing.Union['Modint', int]) -> 'Modint': 92 | if isinstance(rhs, Modint): 93 | result = self._v + rhs._v 94 | if result >= self._mod: 95 | result -= self._mod 96 | return raw(result) 97 | else: 98 | return Modint(self._v + rhs) 99 | 100 | def __sub__(self, rhs: typing.Union['Modint', int]) -> 'Modint': 101 | if isinstance(rhs, Modint): 102 | result = self._v - rhs._v 103 | if result < 0: 104 | result += self._mod 105 | return raw(result) 106 | else: 107 | return Modint(self._v - rhs) 108 | 109 | def __mul__(self, rhs: typing.Union['Modint', int]) -> 'Modint': 110 | if isinstance(rhs, Modint): 111 | return Modint(self._v * rhs._v) 112 | else: 113 | return Modint(self._v * rhs) 114 | 115 | def __floordiv__(self, rhs: typing.Union['Modint', int]) -> 'Modint': 116 | if isinstance(rhs, Modint): 117 | inv = rhs.inv()._v 118 | else: 119 | inv = atcoder._math._inv_gcd(rhs, self._mod)[1] 120 | return Modint(self._v * inv) 121 | 122 | def __eq__(self, rhs: typing.Union['Modint', int]) -> bool: # type: ignore 123 | if isinstance(rhs, Modint): 124 | return self._v == rhs._v 125 | else: 126 | return self._v == rhs 127 | 128 | def __ne__(self, rhs: typing.Union['Modint', int]) -> bool: # type: ignore 129 | if isinstance(rhs, Modint): 130 | return self._v != rhs._v 131 | else: 132 | return self._v != rhs 133 | 134 | 135 | def raw(v: int) -> Modint: 136 | x = Modint() 137 | x._v = v 138 | return x 139 | -------------------------------------------------------------------------------- /atcoder/scc.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | import atcoder._scc 4 | 5 | 6 | class SCCGraph: 7 | def __init__(self, n: int = 0) -> None: 8 | self._internal = atcoder._scc.SCCGraph(n) 9 | 10 | def add_edge(self, from_vertex: int, to_vertex: int) -> None: 11 | n = self._internal.num_vertices() 12 | assert 0 <= from_vertex < n 13 | assert 0 <= to_vertex < n 14 | self._internal.add_edge(from_vertex, to_vertex) 15 | 16 | def scc(self) -> typing.List[typing.List[int]]: 17 | return self._internal.scc() 18 | -------------------------------------------------------------------------------- /atcoder/segtree.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | import atcoder._bit 4 | 5 | 6 | class SegTree: 7 | def __init__(self, 8 | op: typing.Callable[[typing.Any, typing.Any], typing.Any], 9 | e: typing.Any, 10 | v: typing.Union[int, typing.List[typing.Any]]) -> None: 11 | self._op = op 12 | self._e = e 13 | 14 | if isinstance(v, int): 15 | v = [e] * v 16 | 17 | self._n = len(v) 18 | self._log = atcoder._bit._ceil_pow2(self._n) 19 | self._size = 1 << self._log 20 | self._d = [e] * (2 * self._size) 21 | 22 | for i in range(self._n): 23 | self._d[self._size + i] = v[i] 24 | for i in range(self._size - 1, 0, -1): 25 | self._update(i) 26 | 27 | def set(self, p: int, x: typing.Any) -> None: 28 | assert 0 <= p < self._n 29 | 30 | p += self._size 31 | self._d[p] = x 32 | for i in range(1, self._log + 1): 33 | self._update(p >> i) 34 | 35 | def get(self, p: int) -> typing.Any: 36 | assert 0 <= p < self._n 37 | 38 | return self._d[p + self._size] 39 | 40 | def prod(self, left: int, right: int) -> typing.Any: 41 | assert 0 <= left <= right <= self._n 42 | sml = self._e 43 | smr = self._e 44 | left += self._size 45 | right += self._size 46 | 47 | while left < right: 48 | if left & 1: 49 | sml = self._op(sml, self._d[left]) 50 | left += 1 51 | if right & 1: 52 | right -= 1 53 | smr = self._op(self._d[right], smr) 54 | left >>= 1 55 | right >>= 1 56 | 57 | return self._op(sml, smr) 58 | 59 | def all_prod(self) -> typing.Any: 60 | return self._d[1] 61 | 62 | def max_right(self, left: int, 63 | f: typing.Callable[[typing.Any], bool]) -> int: 64 | assert 0 <= left <= self._n 65 | assert f(self._e) 66 | 67 | if left == self._n: 68 | return self._n 69 | 70 | left += self._size 71 | sm = self._e 72 | 73 | first = True 74 | while first or (left & -left) != left: 75 | first = False 76 | while left % 2 == 0: 77 | left >>= 1 78 | if not f(self._op(sm, self._d[left])): 79 | while left < self._size: 80 | left *= 2 81 | if f(self._op(sm, self._d[left])): 82 | sm = self._op(sm, self._d[left]) 83 | left += 1 84 | return left - self._size 85 | sm = self._op(sm, self._d[left]) 86 | left += 1 87 | 88 | return self._n 89 | 90 | def min_left(self, right: int, 91 | f: typing.Callable[[typing.Any], bool]) -> int: 92 | assert 0 <= right <= self._n 93 | assert f(self._e) 94 | 95 | if right == 0: 96 | return 0 97 | 98 | right += self._size 99 | sm = self._e 100 | 101 | first = True 102 | while first or (right & -right) != right: 103 | first = False 104 | right -= 1 105 | while right > 1 and right % 2: 106 | right >>= 1 107 | if not f(self._op(self._d[right], sm)): 108 | while right < self._size: 109 | right = 2 * right + 1 110 | if f(self._op(self._d[right], sm)): 111 | sm = self._op(self._d[right], sm) 112 | right -= 1 113 | return right + 1 - self._size 114 | sm = self._op(self._d[right], sm) 115 | 116 | return 0 117 | 118 | def _update(self, k: int) -> None: 119 | self._d[k] = self._op(self._d[2 * k], self._d[2 * k + 1]) 120 | -------------------------------------------------------------------------------- /atcoder/string.py: -------------------------------------------------------------------------------- 1 | import functools 2 | import typing 3 | 4 | 5 | def _sa_naive(s: typing.List[int]) -> typing.List[int]: 6 | sa = list(range(len(s))) 7 | return sorted(sa, key=lambda i: s[i:]) 8 | 9 | 10 | def _sa_doubling(s: typing.List[int]) -> typing.List[int]: 11 | n = len(s) 12 | sa = list(range(n)) 13 | rnk = s.copy() 14 | tmp = [0] * n 15 | k = 1 16 | while k < n: 17 | def cmp(x: int, y: int) -> int: 18 | if rnk[x] != rnk[y]: 19 | return rnk[x] - rnk[y] 20 | rx = rnk[x + k] if x + k < n else -1 21 | ry = rnk[y + k] if y + k < n else -1 22 | return rx - ry 23 | sa.sort(key=functools.cmp_to_key(cmp)) 24 | tmp[sa[0]] = 0 25 | for i in range(1, n): 26 | tmp[sa[i]] = tmp[sa[i - 1]] + (1 if cmp(sa[i - 1], sa[i]) else 0) 27 | tmp, rnk = rnk, tmp 28 | k *= 2 29 | return sa 30 | 31 | 32 | def _sa_is(s: typing.List[int], upper: int) -> typing.List[int]: 33 | threshold_naive = 10 34 | threshold_doubling = 40 35 | 36 | n = len(s) 37 | 38 | if n == 0: 39 | return [] 40 | if n == 1: 41 | return [0] 42 | if n == 2: 43 | if s[0] < s[1]: 44 | return [0, 1] 45 | else: 46 | return [1, 0] 47 | 48 | if n < threshold_naive: 49 | return _sa_naive(s) 50 | if n < threshold_doubling: 51 | return _sa_doubling(s) 52 | 53 | sa = [0] * n 54 | ls = [False] * n 55 | for i in range(n - 2, -1, -1): 56 | if s[i] == s[i + 1]: 57 | ls[i] = ls[i + 1] 58 | else: 59 | ls[i] = s[i] < s[i + 1] 60 | 61 | sum_l = [0] * (upper + 1) 62 | sum_s = [0] * (upper + 1) 63 | for i in range(n): 64 | if not ls[i]: 65 | sum_s[s[i]] += 1 66 | else: 67 | sum_l[s[i] + 1] += 1 68 | for i in range(upper + 1): 69 | sum_s[i] += sum_l[i] 70 | if i < upper: 71 | sum_l[i + 1] += sum_s[i] 72 | 73 | def induce(lms: typing.List[int]) -> None: 74 | nonlocal sa 75 | sa = [-1] * n 76 | 77 | buf = sum_s.copy() 78 | for d in lms: 79 | if d == n: 80 | continue 81 | sa[buf[s[d]]] = d 82 | buf[s[d]] += 1 83 | 84 | buf = sum_l.copy() 85 | sa[buf[s[n - 1]]] = n - 1 86 | buf[s[n - 1]] += 1 87 | for i in range(n): 88 | v = sa[i] 89 | if v >= 1 and not ls[v - 1]: 90 | sa[buf[s[v - 1]]] = v - 1 91 | buf[s[v - 1]] += 1 92 | 93 | buf = sum_l.copy() 94 | for i in range(n - 1, -1, -1): 95 | v = sa[i] 96 | if v >= 1 and ls[v - 1]: 97 | buf[s[v - 1] + 1] -= 1 98 | sa[buf[s[v - 1] + 1]] = v - 1 99 | 100 | lms_map = [-1] * (n + 1) 101 | m = 0 102 | for i in range(1, n): 103 | if not ls[i - 1] and ls[i]: 104 | lms_map[i] = m 105 | m += 1 106 | lms = [] 107 | for i in range(1, n): 108 | if not ls[i - 1] and ls[i]: 109 | lms.append(i) 110 | 111 | induce(lms) 112 | 113 | if m: 114 | sorted_lms = [] 115 | for v in sa: 116 | if lms_map[v] != -1: 117 | sorted_lms.append(v) 118 | rec_s = [0] * m 119 | rec_upper = 0 120 | rec_s[lms_map[sorted_lms[0]]] = 0 121 | for i in range(1, m): 122 | left = sorted_lms[i - 1] 123 | right = sorted_lms[i] 124 | if lms_map[left] + 1 < m: 125 | end_l = lms[lms_map[left] + 1] 126 | else: 127 | end_l = n 128 | if lms_map[right] + 1 < m: 129 | end_r = lms[lms_map[right] + 1] 130 | else: 131 | end_r = n 132 | 133 | same = True 134 | if end_l - left != end_r - right: 135 | same = False 136 | else: 137 | while left < end_l: 138 | if s[left] != s[right]: 139 | break 140 | left += 1 141 | right += 1 142 | if left == n or s[left] != s[right]: 143 | same = False 144 | 145 | if not same: 146 | rec_upper += 1 147 | rec_s[lms_map[sorted_lms[i]]] = rec_upper 148 | 149 | rec_sa = _sa_is(rec_s, rec_upper) 150 | 151 | for i in range(m): 152 | sorted_lms[i] = lms[rec_sa[i]] 153 | induce(sorted_lms) 154 | 155 | return sa 156 | 157 | 158 | def suffix_array(s: typing.Union[str, typing.List[int]], 159 | upper: typing.Optional[int] = None) -> typing.List[int]: 160 | ''' 161 | SA-IS, linear-time suffix array construction 162 | Reference: 163 | G. Nong, S. Zhang, and W. H. Chan, 164 | Two Efficient Algorithms for Linear Time Suffix Array Construction 165 | ''' 166 | 167 | if isinstance(s, str): 168 | return _sa_is([ord(c) for c in s], 255) 169 | elif upper is None: 170 | n = len(s) 171 | idx = list(range(n)) 172 | 173 | def cmp(left: int, right: int) -> int: 174 | return typing.cast(int, s[left]) - typing.cast(int, s[right]) 175 | 176 | idx.sort(key=functools.cmp_to_key(cmp)) 177 | s2 = [0] * n 178 | now = 0 179 | for i in range(n): 180 | if i and s[idx[i - 1]] != s[idx[i]]: 181 | now += 1 182 | s2[idx[i]] = now 183 | return _sa_is(s2, now) 184 | else: 185 | assert 0 <= upper 186 | for d in s: 187 | assert 0 <= d <= upper 188 | 189 | return _sa_is(s, upper) 190 | 191 | 192 | def lcp_array(s: typing.Union[str, typing.List[int]], 193 | sa: typing.List[int]) -> typing.List[int]: 194 | ''' 195 | Longest-Common-Prefix computation 196 | Reference: 197 | T. Kasai, G. Lee, H. Arimura, S. Arikawa, and K. Park, 198 | Linear-Time Longest-Common-Prefix Computation in Suffix Arrays and Its 199 | Applications 200 | ''' 201 | 202 | if isinstance(s, str): 203 | s = [ord(c) for c in s] 204 | 205 | n = len(s) 206 | assert n >= 1 207 | 208 | rnk = [0] * n 209 | for i in range(n): 210 | rnk[sa[i]] = i 211 | 212 | lcp = [0] * (n - 1) 213 | h = 0 214 | for i in range(n): 215 | if h > 0: 216 | h -= 1 217 | if rnk[i] == 0: 218 | continue 219 | j = sa[rnk[i] - 1] 220 | while j + h < n and i + h < n: 221 | if s[j + h] != s[i + h]: 222 | break 223 | h += 1 224 | lcp[rnk[i] - 1] = h 225 | 226 | return lcp 227 | 228 | 229 | def z_algorithm(s: typing.Union[str, typing.List[int]]) -> typing.List[int]: 230 | ''' 231 | Z algorithm 232 | Reference: 233 | D. Gusfield, 234 | Algorithms on Strings, Trees, and Sequences: Computer Science and 235 | Computational Biology 236 | ''' 237 | 238 | if isinstance(s, str): 239 | s = [ord(c) for c in s] 240 | 241 | n = len(s) 242 | if n == 0: 243 | return [] 244 | 245 | z = [0] * n 246 | j = 0 247 | for i in range(1, n): 248 | z[i] = 0 if j + z[j] <= i else min(j + z[j] - i, z[i - j]) 249 | while i + z[i] < n and s[z[i]] == s[i + z[i]]: 250 | z[i] += 1 251 | if j + z[j] < i + z[i]: 252 | j = i 253 | z[0] = n 254 | 255 | return z 256 | -------------------------------------------------------------------------------- /atcoder/twosat.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | import atcoder._scc 4 | 5 | 6 | class TwoSAT: 7 | ''' 8 | 2-SAT 9 | 10 | Reference: 11 | B. Aspvall, M. Plass, and R. Tarjan, 12 | A Linear-Time Algorithm for Testing the Truth of Certain Quantified Boolean 13 | Formulas 14 | ''' 15 | 16 | def __init__(self, n: int = 0) -> None: 17 | self._n = n 18 | self._answer = [False] * n 19 | self._scc = atcoder._scc.SCCGraph(2 * n) 20 | 21 | def add_clause(self, i: int, f: bool, j: int, g: bool) -> None: 22 | assert 0 <= i < self._n 23 | assert 0 <= j < self._n 24 | 25 | self._scc.add_edge(2 * i + (0 if f else 1), 2 * j + (1 if g else 0)) 26 | self._scc.add_edge(2 * j + (0 if g else 1), 2 * i + (1 if f else 0)) 27 | 28 | def satisfiable(self) -> bool: 29 | scc_id = self._scc.scc_ids()[1] 30 | for i in range(self._n): 31 | if scc_id[2 * i] == scc_id[2 * i + 1]: 32 | return False 33 | self._answer[i] = scc_id[2 * i] < scc_id[2 * i + 1] 34 | return True 35 | 36 | def answer(self) -> typing.List[bool]: 37 | return self._answer 38 | -------------------------------------------------------------------------------- /benchmarks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not522/ac-library-python/27fdbb71cd0d566bdeb12746db59c9d908c6b5d5/benchmarks/__init__.py -------------------------------------------------------------------------------- /benchmarks/benchmark_dsu.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | from atcoder.dsu import DSU 4 | 5 | 6 | class DSUSuite: 7 | 8 | def setup(self) -> None: 9 | random.seed(0) 10 | self.n = 100000 11 | self.pairs = [] 12 | for _ in range(1000000): 13 | a = random.randrange(0, self.n) 14 | b = random.randrange(0, self.n) 15 | self.pairs.append((a, b)) 16 | 17 | def time_dsu_merge(self) -> None: 18 | dsu = DSU(self.n) 19 | for i, j in self.pairs: 20 | dsu.merge(i, j) 21 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | clean: 16 | rm -rf $(BUILDDIR) generated 17 | 18 | .PHONY: help clean Makefile 19 | 20 | # Catch-all target: route all unknown targets to Sphinx using the new 21 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 22 | %: Makefile 23 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 24 | -------------------------------------------------------------------------------- /docs/_templates/autosummary/class.rst: -------------------------------------------------------------------------------- 1 | {{ fullname }} 2 | {{ underline }} 3 | 4 | .. currentmodule:: {{ module }} 5 | 6 | .. autoclass:: {{ objname }} 7 | 8 | {% block methods %} 9 | .. rubric:: Methods 10 | {% for item in methods %} 11 | .. automethod:: {{ item }} 12 | {%- endfor %} 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | import os 14 | import sys 15 | sys.path.insert(0, os.path.abspath('..')) 16 | 17 | 18 | # -- Project information ----------------------------------------------------- 19 | 20 | project = 'ac-library-python' 21 | copyright = '2020, Naoto Mizuno' 22 | author = 'Naoto Mizuno' 23 | 24 | 25 | # -- General configuration --------------------------------------------------- 26 | 27 | # Add any Sphinx extension module names here, as strings. They can be 28 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 29 | # ones. 30 | extensions = ['sphinx.ext.autodoc', 31 | 'sphinx.ext.autosummary', 32 | 'sphinx.ext.napoleon', 33 | ] 34 | 35 | autosummary_generate = True 36 | 37 | # Add any paths that contain templates here, relative to this directory. 38 | templates_path = ['_templates'] 39 | 40 | # List of patterns, relative to source directory, that match files and 41 | # directories to ignore when looking for source files. 42 | # This pattern also affects html_static_path and html_extra_path. 43 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 44 | 45 | 46 | # -- Options for HTML output ------------------------------------------------- 47 | 48 | # The theme to use for HTML and HTML Help pages. See the documentation for 49 | # a list of builtin themes. 50 | # 51 | html_theme = 'sphinx_rtd_theme' 52 | 53 | # Add any paths that contain custom static files (such as style sheets) here, 54 | # relative to this directory. They are copied after the builtin static files, 55 | # so a file named "default.css" will overwrite the builtin "default.css". 56 | html_static_path = ['_static'] 57 | 58 | master_doc = 'index' 59 | -------------------------------------------------------------------------------- /docs/convolution.rst: -------------------------------------------------------------------------------- 1 | Convolution 2 | =========== 3 | 4 | .. autosummary:: 5 | :toctree: generated/ 6 | :nosignatures: 7 | 8 | atcoder.convolution.convolution 9 | atcoder.convolution.convolution_int 10 | -------------------------------------------------------------------------------- /docs/dsu.rst: -------------------------------------------------------------------------------- 1 | Disjoint Union Set 2 | ================== 3 | 4 | .. autosummary:: 5 | :toctree: generated/ 6 | :nosignatures: 7 | 8 | atcoder.dsu.DSU 9 | -------------------------------------------------------------------------------- /docs/fenwicktree.rst: -------------------------------------------------------------------------------- 1 | Fenwick Tree 2 | ============ 3 | 4 | .. autosummary:: 5 | :toctree: generated/ 6 | :nosignatures: 7 | 8 | atcoder.fenwicktree.FenwickTree 9 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | 2 | ac-library-python: Python port of AtCoder Library. 3 | ================================================== 4 | 5 | .. toctree:: 6 | :maxdepth: 1 7 | :caption: Data Structures: 8 | 9 | fenwicktree 10 | segtree 11 | lazysegtree 12 | string 13 | 14 | .. toctree:: 15 | :maxdepth: 1 16 | :caption: Math: 17 | 18 | math 19 | convolution 20 | modint 21 | 22 | .. toctree:: 23 | :maxdepth: 1 24 | :caption: Graphs: 25 | 26 | dsu 27 | maxflow 28 | mincostflow 29 | scc 30 | twosat 31 | 32 | 33 | Indices and tables 34 | ================== 35 | 36 | * :ref:`genindex` 37 | * :ref:`modindex` 38 | * :ref:`search` 39 | -------------------------------------------------------------------------------- /docs/lazysegtree.rst: -------------------------------------------------------------------------------- 1 | Lazy Segment Tree 2 | ================= 3 | 4 | .. autosummary:: 5 | :toctree: generated/ 6 | :nosignatures: 7 | 8 | atcoder.lazysegtree.LazySegTree 9 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/math.rst: -------------------------------------------------------------------------------- 1 | Math 2 | ==== 3 | 4 | .. autosummary:: 5 | :toctree: generated/ 6 | :nosignatures: 7 | 8 | atcoder.math.inv_mod 9 | atcoder.math.crt 10 | atcoder.math.floor_sum 11 | atcoder.math.pow_mod 12 | -------------------------------------------------------------------------------- /docs/maxflow.rst: -------------------------------------------------------------------------------- 1 | Maximum Flow 2 | ============ 3 | 4 | .. autosummary:: 5 | :toctree: generated/ 6 | :nosignatures: 7 | 8 | atcoder.maxflow.MFGraph 9 | -------------------------------------------------------------------------------- /docs/mincostflow.rst: -------------------------------------------------------------------------------- 1 | Minimum-Cost Flow 2 | ================= 3 | 4 | .. autosummary:: 5 | :toctree: generated/ 6 | :nosignatures: 7 | 8 | atcoder.mincostflow.MCFGraph 9 | -------------------------------------------------------------------------------- /docs/modint.rst: -------------------------------------------------------------------------------- 1 | Modint 2 | ====== 3 | 4 | .. autosummary:: 5 | :toctree: generated/ 6 | :nosignatures: 7 | 8 | atcoder.modint.Modint 9 | -------------------------------------------------------------------------------- /docs/scc.rst: -------------------------------------------------------------------------------- 1 | Strongly Connected Components 2 | ============================= 3 | 4 | .. autosummary:: 5 | :toctree: generated/ 6 | :nosignatures: 7 | 8 | atcoder.scc.SCCGraph 9 | -------------------------------------------------------------------------------- /docs/segtree.rst: -------------------------------------------------------------------------------- 1 | Segment Tree 2 | ============ 3 | 4 | .. autosummary:: 5 | :toctree: generated/ 6 | :nosignatures: 7 | 8 | atcoder.segtree.SegTree 9 | -------------------------------------------------------------------------------- /docs/string.rst: -------------------------------------------------------------------------------- 1 | String Algorithms 2 | ================= 3 | 4 | .. autosummary:: 5 | :toctree: generated/ 6 | :nosignatures: 7 | 8 | atcoder.string.suffix_array 9 | atcoder.string.lcp_array 10 | atcoder.string.z_algorithm 11 | -------------------------------------------------------------------------------- /docs/twosat.rst: -------------------------------------------------------------------------------- 1 | 2-SAT 2 | ===== 3 | 4 | .. autosummary:: 5 | :toctree: generated/ 6 | :nosignatures: 7 | 8 | atcoder.twosat.TwoSAT 9 | -------------------------------------------------------------------------------- /example/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not522/ac-library-python/27fdbb71cd0d566bdeb12746db59c9d908c6b5d5/example/__init__.py -------------------------------------------------------------------------------- /example/convolution_practice.py: -------------------------------------------------------------------------------- 1 | # https://atcoder.jp/contests/practice2/tasks/practice2_f 2 | 3 | import sys 4 | 5 | from atcoder.convolution import convolution 6 | 7 | 8 | def main() -> None: 9 | n, m = map(int, sys.stdin.readline().split()) 10 | a = list(map(int, sys.stdin.readline().split())) 11 | b = list(map(int, sys.stdin.readline().split())) 12 | 13 | c = convolution(998244353, a, b) 14 | 15 | print(' '.join(map(str, c))) 16 | 17 | 18 | if __name__ == '__main__': 19 | main() 20 | -------------------------------------------------------------------------------- /example/convolution_practice_int.py: -------------------------------------------------------------------------------- 1 | # https://atcoder.jp/contests/practice2/tasks/practice2_f 2 | 3 | import sys 4 | 5 | from atcoder.convolution import convolution_int 6 | 7 | 8 | def main() -> None: 9 | n, m = map(int, sys.stdin.readline().split()) 10 | a = list(map(int, sys.stdin.readline().split())) 11 | b = list(map(int, sys.stdin.readline().split())) 12 | 13 | c = convolution_int(a, b) 14 | 15 | print(' '.join([str(ci % 998244353) for ci in c])) 16 | 17 | 18 | if __name__ == '__main__': 19 | main() 20 | -------------------------------------------------------------------------------- /example/dsu_practice.py: -------------------------------------------------------------------------------- 1 | # https://atcoder.jp/contests/practice2/tasks/practice2_a 2 | 3 | import sys 4 | 5 | from atcoder.dsu import DSU 6 | 7 | 8 | def main() -> None: 9 | n, q = map(int, sys.stdin.readline().split()) 10 | dsu = DSU(n) 11 | 12 | for _ in range(q): 13 | t, u, v = map(int, sys.stdin.readline().split()) 14 | if t == 0: 15 | dsu.merge(u, v) 16 | if t == 1: 17 | if dsu.same(u, v): 18 | print(1) 19 | else: 20 | print(0) 21 | 22 | 23 | if __name__ == '__main__': 24 | main() 25 | -------------------------------------------------------------------------------- /example/fenwick_practice.py: -------------------------------------------------------------------------------- 1 | # https://atcoder.jp/contests/practice2/tasks/practice2_b 2 | 3 | import sys 4 | 5 | from atcoder.fenwicktree import FenwickTree 6 | 7 | 8 | def main() -> None: 9 | n, q = map(int, sys.stdin.readline().split()) 10 | fenwick_tree = FenwickTree(n) 11 | 12 | a = map(int, sys.stdin.readline().split()) 13 | for i, ai in enumerate(a): 14 | fenwick_tree.add(i, ai) 15 | 16 | for _ in range(q): 17 | t, x, y = map(int, sys.stdin.readline().split()) 18 | if t == 0: 19 | fenwick_tree.add(x, y) 20 | if t == 1: 21 | print(fenwick_tree.sum(x, y)) 22 | 23 | 24 | if __name__ == '__main__': 25 | main() 26 | -------------------------------------------------------------------------------- /example/floor_sum_practice.py: -------------------------------------------------------------------------------- 1 | # https://atcoder.jp/contests/practice2/tasks/practice2_c 2 | 3 | import sys 4 | 5 | from atcoder.math import floor_sum 6 | 7 | 8 | def main() -> None: 9 | t = int(sys.stdin.readline()) 10 | for _ in range(t): 11 | n, m, a, b = map(int, sys.stdin.readline().split()) 12 | print(floor_sum(n, m, a, b)) 13 | 14 | 15 | if __name__ == '__main__': 16 | main() 17 | -------------------------------------------------------------------------------- /example/lazysegtree_practice_k.py: -------------------------------------------------------------------------------- 1 | # https://atcoder.jp/contests/practice2/tasks/practice2_k 2 | 3 | import sys 4 | from typing import Tuple 5 | 6 | from atcoder.lazysegtree import LazySegTree 7 | from atcoder.modint import ModContext, Modint 8 | 9 | 10 | def main() -> None: 11 | with ModContext(998244353): 12 | n, q = map(int, sys.stdin.readline().split()) 13 | a = [(Modint(ai), 1) for ai in map(int, sys.stdin.readline().split())] 14 | 15 | def op(x: Tuple[Modint, int], 16 | y: Tuple[Modint, int]) -> Tuple[Modint, int]: 17 | return x[0] + y[0], x[1] + y[1] 18 | 19 | e = Modint(0), 0 20 | 21 | def mapping(x: Tuple[Modint, Modint], 22 | y: Tuple[Modint, int]) -> Tuple[Modint, int]: 23 | return x[0] * y[0] + x[1] * y[1], y[1] 24 | 25 | def composition(x: Tuple[Modint, Modint], 26 | y: Tuple[Modint, Modint]) -> Tuple[Modint, Modint]: 27 | return x[0] * y[0], x[0] * y[1] + x[1] 28 | 29 | id_ = Modint(1), Modint(0) 30 | 31 | lazy_segtree = LazySegTree(op, e, mapping, composition, id_, a) 32 | 33 | for _ in range(q): 34 | t, *inputs = map(int, sys.stdin.readline().split()) 35 | if t == 0: 36 | l, r, b, c = inputs 37 | lazy_segtree.apply(l, r, (Modint(b), Modint(c))) 38 | else: 39 | l, r = inputs 40 | print(lazy_segtree.prod(l, r)[0].val()) 41 | 42 | 43 | if __name__ == '__main__': 44 | main() 45 | -------------------------------------------------------------------------------- /example/lazysegtree_practice_k_wo_modint.py: -------------------------------------------------------------------------------- 1 | # https://atcoder.jp/contests/practice2/tasks/practice2_k 2 | 3 | import sys 4 | from typing import Tuple 5 | 6 | from atcoder.lazysegtree import LazySegTree 7 | 8 | 9 | def main() -> None: 10 | mod = 998244353 11 | 12 | n, q = map(int, sys.stdin.readline().split()) 13 | a = [(ai, 1) for ai in map(int, sys.stdin.readline().split())] 14 | 15 | def op(x: Tuple[int, int], y: Tuple[int, int]) -> Tuple[int, int]: 16 | return (x[0] + y[0]) % mod, x[1] + y[1] 17 | 18 | e = 0, 0 19 | 20 | def mapping(x: Tuple[int, int], y: Tuple[int, int]) -> Tuple[int, int]: 21 | return (x[0] * y[0] + x[1] * y[1]) % mod, y[1] 22 | 23 | def composition(x: Tuple[int, int], y: Tuple[int, int]) -> Tuple[int, int]: 24 | return (x[0] * y[0]) % mod, (x[0] * y[1] + x[1]) % mod 25 | 26 | id_ = 1, 0 27 | 28 | lazy_segtree = LazySegTree(op, e, mapping, composition, id_, a) 29 | 30 | for _ in range(q): 31 | t, *inputs = map(int, sys.stdin.readline().split()) 32 | if t == 0: 33 | l, r, b, c = inputs 34 | lazy_segtree.apply(l, r, (b, c)) 35 | else: 36 | l, r = inputs 37 | print(lazy_segtree.prod(l, r)[0]) 38 | 39 | 40 | if __name__ == '__main__': 41 | main() 42 | -------------------------------------------------------------------------------- /example/lazysegtree_practice_l.py: -------------------------------------------------------------------------------- 1 | # https://atcoder.jp/contests/practice2/tasks/practice2_l 2 | 3 | import sys 4 | from typing import Tuple 5 | 6 | from atcoder.lazysegtree import LazySegTree 7 | 8 | 9 | def main() -> None: 10 | n, q = map(int, sys.stdin.readline().split()) 11 | a = [] 12 | for x in map(int, sys.stdin.readline().split()): 13 | if x == 0: 14 | a.append((1, 0, 0)) 15 | else: 16 | a.append((0, 1, 0)) 17 | 18 | def op(x: Tuple[int, int, int], 19 | y: Tuple[int, int, int]) -> Tuple[int, int, int]: 20 | return x[0] + y[0], x[1] + y[1], x[2] + y[2] + x[1] * y[0] 21 | 22 | e = (0, 0, 0) 23 | 24 | def mapping(x: bool, y: Tuple[int, int, int]) -> Tuple[int, int, int]: 25 | if not x: 26 | return y 27 | return y[1], y[0], y[0] * y[1] - y[2] 28 | 29 | def composition(x: bool, y: bool) -> bool: 30 | return (x and not y) or (not x and y) 31 | 32 | id_ = False 33 | 34 | lazy_segtree = LazySegTree(op, e, mapping, composition, id_, a) 35 | for _ in range(q): 36 | t, left, right = map(int, sys.stdin.readline().split()) 37 | left -= 1 38 | if t == 1: 39 | lazy_segtree.apply(left, right, True) 40 | else: 41 | print(lazy_segtree.prod(left, right)[2]) 42 | 43 | 44 | if __name__ == '__main__': 45 | main() 46 | -------------------------------------------------------------------------------- /example/maxflow_practice.py: -------------------------------------------------------------------------------- 1 | # https://atcoder.jp/contests/practice2/tasks/practice2_d 2 | 3 | import sys 4 | from typing import Tuple 5 | 6 | from atcoder.maxflow import MFGraph 7 | 8 | 9 | def main() -> None: 10 | n, m = map(int, sys.stdin.readline().split()) 11 | s = n * m 12 | t = s + 1 13 | g = MFGraph(t + 1) 14 | grid = [list(sys.stdin.readline().strip()) for _ in range(n)] 15 | 16 | def enc(i: int, j: int) -> int: 17 | return i * m + j 18 | 19 | def dec(v: int) -> Tuple[int, int]: 20 | return v // m, v % m 21 | 22 | for i in range(n): 23 | for j in range(m): 24 | if grid[i][j] == '#': 25 | continue 26 | if (i + j) % 2 == 0: 27 | g.add_edge(s, enc(i, j), 1) 28 | else: 29 | g.add_edge(enc(i, j), t, 1) 30 | 31 | dx = [1, 0, -1, 0] 32 | dy = [0, 1, 0, -1] 33 | for i in range(n): 34 | for j in range(m): 35 | if (i + j) % 2 == 1 or grid[i][j] == '#': 36 | continue 37 | for direction in range(4): 38 | ii = i + dx[direction] 39 | jj = j + dy[direction] 40 | if 0 <= ii < n and 0 <= jj < m and grid[ii][jj] == '.': 41 | g.add_edge(enc(i, j), enc(ii, jj), 1) 42 | 43 | print(g.flow(s, t)) 44 | for e in g.edges(): 45 | if e.src == s or e.dst == t or e.flow == 0: 46 | continue 47 | (i, j) = dec(e.src) 48 | (ii, jj) = dec(e.dst) 49 | if i == ii + 1: 50 | grid[ii][jj] = 'v' 51 | grid[i][j] = '^' 52 | elif j == jj + 1: 53 | grid[ii][jj] = '>' 54 | grid[i][j] = '<' 55 | elif i == ii - 1: 56 | grid[i][j] = 'v' 57 | grid[ii][jj] = '^' 58 | else: 59 | grid[i][j] = '>' 60 | grid[ii][jj] = '<' 61 | 62 | for r in grid: 63 | print("".join(r)) 64 | 65 | 66 | if __name__ == '__main__': 67 | main() 68 | -------------------------------------------------------------------------------- /example/mincostflow_practice.py: -------------------------------------------------------------------------------- 1 | # https://atcoder.jp/contests/practice2/tasks/practice2_e 2 | 3 | import sys 4 | from typing import List 5 | 6 | from atcoder.mincostflow import MCFGraph 7 | 8 | 9 | def main() -> None: 10 | n, k = map(int, sys.stdin.readline().split()) 11 | s = n * 2 12 | t = s + 1 13 | g = MCFGraph(t + 1) 14 | grid = [list(map(int, sys.stdin.readline().split())) for _ in range(n)] 15 | big = 10 ** 9 16 | edges: List[List[int]] = list([] for _ in range(n)) 17 | for i in range(n): 18 | g.add_edge(s, i, k, 0) 19 | g.add_edge(i + n, t, k, 0) 20 | for j in range(n): 21 | edges[i].append(g.add_edge(i, j + n, 1, big - grid[i][j])) 22 | g.add_edge(s, t, n * k, big) 23 | 24 | cost = g.flow(s, t, n * k)[1] 25 | print(big * n * k - cost) 26 | 27 | result = list(['.'] * n for _ in range(n)) 28 | for i in range(n): 29 | for j in range(n): 30 | if g.get_edge(edges[i][j]).flow > 0: 31 | result[i][j] = 'X' 32 | 33 | for r in result: 34 | print("".join(r)) 35 | 36 | 37 | if __name__ == '__main__': 38 | main() 39 | -------------------------------------------------------------------------------- /example/sa_practice.py: -------------------------------------------------------------------------------- 1 | # https://atcoder.jp/contests/practice2/tasks/practice2_i 2 | 3 | import sys 4 | 5 | from atcoder.string import suffix_array, lcp_array 6 | 7 | 8 | def main() -> None: 9 | s = sys.stdin.readline().strip() 10 | sa = suffix_array(s) 11 | 12 | answer = len(s) * (len(s) + 1) // 2 13 | for x in lcp_array(s, sa): 14 | answer -= x 15 | print(answer) 16 | 17 | 18 | if __name__ == '__main__': 19 | main() 20 | -------------------------------------------------------------------------------- /example/scc_practice.py: -------------------------------------------------------------------------------- 1 | # https://atcoder.jp/contests/practice2/tasks/practice2_g 2 | 3 | import sys 4 | 5 | from atcoder.scc import SCCGraph 6 | 7 | 8 | def main() -> None: 9 | n, m = map(int, sys.stdin.readline().split()) 10 | g = SCCGraph(n) 11 | 12 | for i in range(m): 13 | u, v = map(int, sys.stdin.readline().split()) 14 | g.add_edge(u, v) 15 | 16 | scc = g.scc() 17 | 18 | print(len(scc)) 19 | for c in scc: 20 | print(len(c), end='') 21 | for x in c: 22 | print(f' {x}', end='') 23 | print('') 24 | 25 | 26 | if __name__ == '__main__': 27 | main() 28 | -------------------------------------------------------------------------------- /example/segtree_practice.py: -------------------------------------------------------------------------------- 1 | # https://atcoder.jp/contests/practice2/tasks/practice2_j 2 | 3 | import sys 4 | 5 | from atcoder.segtree import SegTree 6 | 7 | 8 | def main() -> None: 9 | n, q = map(int, sys.stdin.readline().split()) 10 | a = list(map(int, sys.stdin.readline().split())) 11 | 12 | segtree = SegTree(max, -1, a) 13 | 14 | for _ in range(q): 15 | t, x, y = map(int, sys.stdin.readline().split()) 16 | if t == 1: 17 | segtree.set(x - 1, y) 18 | elif t == 2: 19 | print(segtree.prod(x - 1, y)) 20 | else: 21 | print(segtree.max_right(x - 1, lambda v: v < y) + 1) 22 | 23 | 24 | if __name__ == '__main__': 25 | main() 26 | -------------------------------------------------------------------------------- /example/segtree_practice_reversed.py: -------------------------------------------------------------------------------- 1 | # https://atcoder.jp/contests/practice2/tasks/practice2_j 2 | 3 | import sys 4 | 5 | from atcoder.segtree import SegTree 6 | 7 | 8 | def main() -> None: 9 | n, q = map(int, sys.stdin.readline().split()) 10 | a = list(map(int, sys.stdin.readline().split()))[::-1] 11 | 12 | segtree = SegTree(max, -1, a) 13 | 14 | for _ in range(q): 15 | t, x, y = map(int, sys.stdin.readline().split()) 16 | if t == 1: 17 | segtree.set(n - x, y) 18 | elif t == 2: 19 | print(segtree.prod(n - y, n - x + 1)) 20 | else: 21 | print(n - segtree.min_left(n - x + 1, lambda v: v < y) + 1) 22 | 23 | 24 | if __name__ == '__main__': 25 | main() 26 | -------------------------------------------------------------------------------- /example/twosat_practice.py: -------------------------------------------------------------------------------- 1 | # https://atcoder.jp/contests/practice2/tasks/practice2_h 2 | 3 | import sys 4 | 5 | from atcoder.twosat import TwoSAT 6 | 7 | 8 | def main() -> None: 9 | n, d = map(int, sys.stdin.readline().split()) 10 | x = [0] * n 11 | y = [0] * n 12 | for i in range(n): 13 | x[i], y[i] = map(int, sys.stdin.readline().split()) 14 | 15 | two_sat = TwoSAT(n) 16 | 17 | for i in range(n): 18 | for j in range(i + 1, n): 19 | if abs(x[i] - x[j]) < d: 20 | two_sat.add_clause(i, False, j, False) 21 | if abs(x[i] - y[j]) < d: 22 | two_sat.add_clause(i, False, j, True) 23 | if abs(y[i] - x[j]) < d: 24 | two_sat.add_clause(i, True, j, False) 25 | if abs(y[i] - y[j]) < d: 26 | two_sat.add_clause(i, True, j, True) 27 | 28 | if not two_sat.satisfiable(): 29 | print("No") 30 | else: 31 | print("Yes") 32 | answer = two_sat.answer() 33 | for i in range(n): 34 | if answer[i]: 35 | print(x[i]) 36 | else: 37 | print(y[i]) 38 | 39 | 40 | if __name__ == '__main__': 41 | main() 42 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = ac-library-python 3 | version = attr: atcoder.__version__ 4 | description = Python port of AtCoder Library (ACL). 5 | license = CC0 6 | 7 | [options] 8 | packages = find: 9 | 10 | [options.extras_require] 11 | lint = 12 | flake8 13 | pep8-naming; python_version>="3.8" 14 | mypy 15 | test = 16 | pytest 17 | docs = 18 | sphinx 19 | sphinx_rtd_theme 20 | benchmark = 21 | asv 22 | virtualenv 23 | 24 | [options.packages.find] 25 | include = atcoder* 26 | 27 | [mypy] 28 | disallow_untyped_defs = True 29 | ignore_missing_imports = True 30 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools # type: ignore 2 | 3 | setuptools.setup() 4 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not522/ac-library-python/27fdbb71cd0d566bdeb12746db59c9d908c6b5d5/tests/__init__.py -------------------------------------------------------------------------------- /tests/example_tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not522/ac-library-python/27fdbb71cd0d566bdeb12746db59c9d908c6b5d5/tests/example_tests/__init__.py -------------------------------------------------------------------------------- /tests/example_tests/input/A1_in.txt: -------------------------------------------------------------------------------- 1 | 4 7 2 | 1 0 1 3 | 0 0 1 4 | 0 2 3 5 | 1 0 1 6 | 1 1 2 7 | 0 0 2 8 | 1 1 3 9 | -------------------------------------------------------------------------------- /tests/example_tests/input/A1_out.txt: -------------------------------------------------------------------------------- 1 | 0 2 | 1 3 | 0 4 | 1 5 | -------------------------------------------------------------------------------- /tests/example_tests/input/B1_in.txt: -------------------------------------------------------------------------------- 1 | 5 5 2 | 1 2 3 4 5 3 | 1 0 5 4 | 1 2 4 5 | 0 3 10 6 | 1 0 5 7 | 1 0 3 8 | -------------------------------------------------------------------------------- /tests/example_tests/input/B1_out.txt: -------------------------------------------------------------------------------- 1 | 15 2 | 7 3 | 25 4 | 6 5 | -------------------------------------------------------------------------------- /tests/example_tests/input/C1_in.txt: -------------------------------------------------------------------------------- 1 | 5 2 | 4 10 6 3 3 | 6 5 4 3 4 | 1 1 0 0 5 | 31415 92653 58979 32384 6 | 1000000000 1000000000 999999999 999999999 7 | -------------------------------------------------------------------------------- /tests/example_tests/input/C1_out.txt: -------------------------------------------------------------------------------- 1 | 3 2 | 13 3 | 0 4 | 314095480 5 | 499999999500000000 6 | -------------------------------------------------------------------------------- /tests/example_tests/input/D1_in.txt: -------------------------------------------------------------------------------- 1 | 3 3 2 | #.. 3 | ..# 4 | ... 5 | -------------------------------------------------------------------------------- /tests/example_tests/input/D1_out.txt: -------------------------------------------------------------------------------- 1 | 3 2 | #>< 3 | ><# 4 | ><. 5 | -------------------------------------------------------------------------------- /tests/example_tests/input/E1_in.txt: -------------------------------------------------------------------------------- 1 | 3 1 2 | 5 3 2 3 | 1 4 8 4 | 7 6 9 5 | -------------------------------------------------------------------------------- /tests/example_tests/input/E1_out.txt: -------------------------------------------------------------------------------- 1 | 19 2 | X.. 3 | ..X 4 | .X. 5 | -------------------------------------------------------------------------------- /tests/example_tests/input/E2_in.txt: -------------------------------------------------------------------------------- 1 | 3 2 2 | 10 10 1 3 | 10 10 1 4 | 1 1 10 5 | -------------------------------------------------------------------------------- /tests/example_tests/input/E2_out.txt: -------------------------------------------------------------------------------- 1 | 50 2 | XX. 3 | XX. 4 | ..X 5 | -------------------------------------------------------------------------------- /tests/example_tests/input/F1_in.txt: -------------------------------------------------------------------------------- 1 | 4 5 2 | 1 2 3 4 3 | 5 6 7 8 9 4 | -------------------------------------------------------------------------------- /tests/example_tests/input/F1_out.txt: -------------------------------------------------------------------------------- 1 | 5 16 34 60 70 70 59 36 2 | -------------------------------------------------------------------------------- /tests/example_tests/input/F2_in.txt: -------------------------------------------------------------------------------- 1 | 1 1 2 | 10000000 3 | 10000000 4 | -------------------------------------------------------------------------------- /tests/example_tests/input/F2_out.txt: -------------------------------------------------------------------------------- 1 | 871938225 2 | -------------------------------------------------------------------------------- /tests/example_tests/input/G1_in.txt: -------------------------------------------------------------------------------- 1 | 6 7 2 | 1 4 3 | 5 2 4 | 3 0 5 | 5 5 6 | 4 1 7 | 0 3 8 | 4 2 9 | -------------------------------------------------------------------------------- /tests/example_tests/input/G1_out.txt: -------------------------------------------------------------------------------- 1 | 4 2 | 1 5 3 | 2 1 4 4 | 1 2 5 | 2 0 3 6 | -------------------------------------------------------------------------------- /tests/example_tests/input/H1_in.txt: -------------------------------------------------------------------------------- 1 | 3 2 2 | 1 4 3 | 2 5 4 | 0 6 5 | -------------------------------------------------------------------------------- /tests/example_tests/input/H1_out.txt: -------------------------------------------------------------------------------- 1 | Yes 2 | 4 3 | 2 4 | 0 5 | -------------------------------------------------------------------------------- /tests/example_tests/input/H2_in.txt: -------------------------------------------------------------------------------- 1 | 3 3 2 | 1 4 3 | 2 5 4 | 0 6 5 | -------------------------------------------------------------------------------- /tests/example_tests/input/H2_out.txt: -------------------------------------------------------------------------------- 1 | No 2 | -------------------------------------------------------------------------------- /tests/example_tests/input/I1_in.txt: -------------------------------------------------------------------------------- 1 | abcbcba 2 | -------------------------------------------------------------------------------- /tests/example_tests/input/I1_out.txt: -------------------------------------------------------------------------------- 1 | 21 2 | -------------------------------------------------------------------------------- /tests/example_tests/input/I2_in.txt: -------------------------------------------------------------------------------- 1 | mississippi 2 | -------------------------------------------------------------------------------- /tests/example_tests/input/I2_out.txt: -------------------------------------------------------------------------------- 1 | 53 2 | -------------------------------------------------------------------------------- /tests/example_tests/input/I3_in.txt: -------------------------------------------------------------------------------- 1 | ababacaca 2 | -------------------------------------------------------------------------------- /tests/example_tests/input/I3_out.txt: -------------------------------------------------------------------------------- 1 | 33 2 | -------------------------------------------------------------------------------- /tests/example_tests/input/I4_in.txt: -------------------------------------------------------------------------------- 1 | aaaaa 2 | -------------------------------------------------------------------------------- /tests/example_tests/input/I4_out.txt: -------------------------------------------------------------------------------- 1 | 5 2 | -------------------------------------------------------------------------------- /tests/example_tests/input/J1_in.txt: -------------------------------------------------------------------------------- 1 | 5 5 2 | 1 2 3 2 1 3 | 2 1 5 4 | 3 2 3 5 | 1 3 1 6 | 2 2 4 7 | 3 1 3 8 | -------------------------------------------------------------------------------- /tests/example_tests/input/J1_out.txt: -------------------------------------------------------------------------------- 1 | 3 2 | 3 3 | 2 4 | 6 5 | -------------------------------------------------------------------------------- /tests/example_tests/input/K1_in.txt: -------------------------------------------------------------------------------- 1 | 5 7 2 | 1 2 3 4 5 3 | 1 0 5 4 | 0 2 4 100 101 5 | 1 0 3 6 | 0 1 3 102 103 7 | 1 2 5 8 | 0 2 5 104 105 9 | 1 0 5 10 | -------------------------------------------------------------------------------- /tests/example_tests/input/K1_out.txt: -------------------------------------------------------------------------------- 1 | 15 2 | 404 3 | 41511 4 | 4317767 5 | -------------------------------------------------------------------------------- /tests/example_tests/input/L1_in.txt: -------------------------------------------------------------------------------- 1 | 5 5 2 | 0 1 0 0 1 3 | 2 1 5 4 | 1 3 4 5 | 2 2 5 6 | 1 1 3 7 | 2 1 2 8 | -------------------------------------------------------------------------------- /tests/example_tests/input/L1_out.txt: -------------------------------------------------------------------------------- 1 | 2 2 | 0 3 | 1 4 | -------------------------------------------------------------------------------- /tests/example_tests/test_examples.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | from subprocess import check_output, run 3 | import sys 4 | from tempfile import NamedTemporaryFile 5 | from typing import TextIO 6 | 7 | import pytest 8 | 9 | 10 | sources = ( 11 | ('A', 'dsu_practice.py'), 12 | ('B', 'fenwick_practice.py'), 13 | ('C', 'floor_sum_practice.py'), 14 | ('D', 'maxflow_practice.py'), 15 | ('E', 'mincostflow_practice.py'), 16 | ('F', 'convolution_practice.py'), 17 | ('F', 'convolution_practice_int.py'), 18 | ('G', 'scc_practice.py'), 19 | ('H', 'twosat_practice.py'), 20 | ('I', 'sa_practice.py'), 21 | ('J', 'segtree_practice.py'), 22 | ('J', 'segtree_practice_reversed.py'), 23 | ('K', 'lazysegtree_practice_k.py'), 24 | ('K', 'lazysegtree_practice_k_wo_modint.py'), 25 | ('L', 'lazysegtree_practice_l.py')) 26 | 27 | 28 | def run_example(source: str, stdin: TextIO) -> str: 29 | source_path = Path(__file__).parent.parent.parent / 'example' / source 30 | output = check_output((sys.executable, source_path), stdin=stdin) 31 | return output.decode() 32 | 33 | 34 | def combine(source: str, output: str) -> None: 35 | source_path = Path(__file__).parent.parent.parent / 'example' / source 36 | run((sys.executable, '-m', 'atcoder', source_path, '-o', output)) 37 | 38 | 39 | class TestExamples: 40 | @pytest.mark.parametrize('problem_id, source', sources) 41 | def test_examples(self, problem_id: str, source: str) -> None: 42 | input_path = (Path(__file__).parent / 'input') 43 | stdin_paths = list(input_path.glob(f'{problem_id}*_in.txt')) 44 | stdout_paths = list(input_path.glob(f'{problem_id}*_out.txt')) 45 | stdin_paths.sort() 46 | stdout_paths.sort() 47 | 48 | for stdin_path, stdout_path in zip(stdin_paths, stdout_paths): 49 | with open(stdin_path) as stdin: 50 | output = run_example(source, stdin) 51 | 52 | with open(stdout_path) as stdout: 53 | assert output == stdout.read() 54 | 55 | @pytest.mark.parametrize('problem_id, source', sources) 56 | def test_combined_examples(self, problem_id: str, source: str) -> None: 57 | with NamedTemporaryFile() as f: 58 | combine(source, f.name) 59 | 60 | input_path = (Path(__file__).parent / 'input') 61 | stdin_paths = list(input_path.glob(f'{problem_id}*_in.txt')) 62 | stdout_paths = list(input_path.glob(f'{problem_id}*_out.txt')) 63 | stdin_paths.sort() 64 | stdout_paths.sort() 65 | 66 | for stdin_path, stdout_path in zip(stdin_paths, stdout_paths): 67 | with open(stdin_path) as stdin: 68 | output = run_example(f.name, stdin) 69 | 70 | with open(stdout_path) as stdout: 71 | assert output == stdout.read() 72 | -------------------------------------------------------------------------------- /tests/test__bit.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from atcoder._bit import _ceil_pow2, _bsf 4 | 5 | 6 | class TestInternalBit: 7 | 8 | @pytest.mark.parametrize(( 9 | 'n', 'expected' 10 | ), [ 11 | (0, 0), 12 | (1, 0), 13 | (2, 1), 14 | (3, 2), 15 | (4, 2), 16 | (5, 3), 17 | (6, 3), 18 | (7, 3), 19 | (8, 3), 20 | (9, 4), 21 | ((1 << 30) - 1, 30), 22 | (1 << 30, 30), 23 | ((1 << 30) + 1, 31), 24 | ((1 << 100) - 1, 100), 25 | (1 << 100, 100), 26 | ((1 << 100) + 1, 101), 27 | ]) 28 | def test_ceil_pow2(self, n: int, expected: int) -> None: 29 | assert _ceil_pow2(n) == expected 30 | 31 | @pytest.mark.parametrize(( 32 | 'n', 'expected' 33 | ), [ 34 | (1, 0), 35 | (2, 1), 36 | (3, 0), 37 | (4, 2), 38 | (5, 0), 39 | (6, 1), 40 | (7, 0), 41 | (8, 3), 42 | (9, 0), 43 | ((1 << 30) - 1, 0), 44 | (1 << 30, 30), 45 | ((1 << 30) + 1, 0), 46 | ((1 << 31) - 1, 0), 47 | (1 << 31, 31), 48 | ((1 << 31) + 1, 0), 49 | ((1 << 100) - 1, 0), 50 | (1 << 100, 100), 51 | ((1 << 100) + 1, 0), 52 | ]) 53 | def test_bsf(self, n: int, expected: int) -> None: 54 | assert _bsf(n) == expected 55 | -------------------------------------------------------------------------------- /tests/test_dsu.py: -------------------------------------------------------------------------------- 1 | from itertools import combinations 2 | import pytest 3 | import random 4 | from typing import List, Tuple 5 | 6 | from atcoder.dsu import DSU 7 | 8 | 9 | class TestDsu: 10 | 11 | def test_initial_status(self) -> None: 12 | dsu = DSU(5) 13 | 14 | for i, j in combinations(range(5), 2): 15 | assert not dsu.same(i, j) 16 | 17 | for index in range(5): 18 | assert dsu.size(index) == 1 19 | assert dsu.leader(index) == index 20 | 21 | assert dsu.groups() == [[0], [1], [2], [3], [4]] 22 | 23 | def test_merge(self) -> None: 24 | dsu = DSU(5) 25 | 26 | assert not dsu.same(0, 1) 27 | 28 | dsu.merge(0, 1) 29 | assert dsu.same(0, 1) 30 | 31 | # Test assertion of invalid pairs 32 | for i in range(-1, 6): 33 | for j in range(-1, 6): 34 | if not (0 <= i < 5 and 0 <= j < 5): 35 | with pytest.raises(AssertionError): 36 | dsu.merge(i, j) 37 | 38 | def test_merge_elements_of_same_group(self) -> None: 39 | dsu = DSU(5) 40 | 41 | assert not dsu.same(0, 1) 42 | 43 | for _ in range(2): 44 | dsu.merge(0, 1) 45 | assert dsu.same(0, 1) 46 | 47 | # Test assertion of invalid pairs 48 | for i in range(-1, 6): 49 | for j in range(-1, 6): 50 | if not (0 <= i < 5 and 0 <= j < 5): 51 | with pytest.raises(AssertionError): 52 | dsu.same(i, j) 53 | 54 | def test_size(self) -> None: 55 | dsu = DSU(5) 56 | 57 | dsu.merge(0, 1) 58 | assert dsu.size(0) == 2 59 | dsu.merge(0, 2) 60 | assert dsu.size(0) == 3 61 | 62 | # Test assertion of invalid indices 63 | for i in (-1, 5): 64 | with pytest.raises(AssertionError): 65 | dsu.size(i) 66 | 67 | def test_leader(self) -> None: 68 | dsu = DSU(5) 69 | 70 | dsu.merge(0, 1) 71 | dsu.merge(0, 2) 72 | 73 | assert dsu.leader(1) in [0, 1, 2] 74 | assert dsu.leader(2) in [0, 1, 2] 75 | assert dsu.leader(1) == dsu.leader(2) 76 | assert dsu.leader(3) not in [0, 1, 2] 77 | assert dsu.leader(4) not in [0, 1, 2] 78 | 79 | # Test assertion of invalid indices 80 | for i in (-1, 5): 81 | with pytest.raises(AssertionError): 82 | dsu.leader(i) 83 | 84 | def test_groups(self) -> None: 85 | dsu = DSU(5) 86 | 87 | dsu.merge(0, 1) 88 | dsu.merge(0, 2) 89 | 90 | assert dsu.groups() == [[0, 1, 2], [3], [4]] 91 | -------------------------------------------------------------------------------- /tests/test_fenwicktree.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from typing import List, Tuple 3 | 4 | from atcoder.fenwicktree import FenwickTree 5 | 6 | 7 | @pytest.fixture 8 | def fenwicktree() -> FenwickTree: 9 | return FenwickTree(5) 10 | 11 | 12 | class TestFenwickTree: 13 | 14 | def test_initial_status(self, fenwicktree: FenwickTree) -> None: 15 | ''' 16 | An initialized fenwicktree object is expected to have all the elements 17 | 0. 18 | 19 | GIVEN an initialized fenwicktree object 20 | WHEN before executing fenwicktree.add(p, x) 21 | THEN all the elements are 0 22 | ''' 23 | 24 | assert fenwicktree.data == [0, 0, 0, 0, 0] 25 | 26 | pair_of_positions = self._generate_pair_of_positions() 27 | 28 | for left, right in pair_of_positions: 29 | assert fenwicktree.sum(left, right) == 0 30 | 31 | def _generate_pair_of_positions(self) -> List[Tuple[int, ...]]: 32 | from itertools import combinations_with_replacement 33 | 34 | return list(combinations_with_replacement(range(5), 2)) 35 | 36 | def test_add(self, fenwicktree: FenwickTree) -> None: 37 | ''' 38 | fenwicktree.add(p, x) is expected to add x to the p-th of the number 39 | sequence. 40 | 41 | GIVEN an initialized fenwicktree object 42 | WHEN add 1 to the first in the number sequence 43 | THEN fenwicktree.data has [1, 1, 0, 1, 0] 44 | ''' 45 | 46 | fenwicktree.add(0, 1) 47 | assert fenwicktree.data == [1, 1, 0, 1, 0] 48 | 49 | def test_add_multiple_times(self, fenwicktree: FenwickTree) -> None: 50 | ''' 51 | fenwicktree.add(p, x) is expected to add x to the p-th of the number 52 | sequence. 53 | 54 | GIVEN an initialized fenwicktree object 55 | WHEN add arbitrary value(s) at arbitrary positions in the sequence 56 | THEN fenwicktree.data has a partial sum at any position in the sequence 57 | ''' 58 | 59 | expected = [[1, 1, 0, 1, 0], 60 | [1, 3, 0, 3, 0], 61 | [1, 3, 3, 6, 0], 62 | [1, 3, 3, 10, 0], 63 | [1, 3, 3, 10, 5] 64 | ] 65 | 66 | for i in range(5): 67 | fenwicktree.add(i, i + 1) 68 | assert fenwicktree.data == expected[i] 69 | 70 | def test_add_when_negative_value_is_given( 71 | self, fenwicktree: FenwickTree 72 | ) -> None: 73 | ''' 74 | fenwicktree.add(p, x) is expected to add x to the p-th of the number 75 | sequence. 76 | 77 | GIVEN an initialized fenwicktree object 78 | WHEN add negative value at arbitrary positions in the sequence 79 | THEN fenwicktree.data has a partial sum at any position in the sequence 80 | ''' 81 | 82 | for i in range(5): 83 | fenwicktree.add(i, i + 1) 84 | 85 | assert fenwicktree.data == [1, 3, 3, 10, 5] 86 | 87 | fenwicktree.add(0, -5) 88 | assert fenwicktree.data == [-4, -2, 3, 5, 5] 89 | 90 | def test_add_when_zero_is_given(self, fenwicktree: FenwickTree) -> None: 91 | ''' 92 | fenwicktree.add(p, x) is expected to add x to the p-th of the number 93 | sequence. 94 | 95 | GIVEN an initialized fenwicktree object 96 | WHEN add zero at arbitrary positions in the sequence 97 | THEN fenwicktree.data has a partial sum at any position in the sequence 98 | ''' 99 | 100 | for i in range(5): 101 | fenwicktree.add(i, i + 1) 102 | 103 | assert fenwicktree.data == [1, 3, 3, 10, 5] 104 | 105 | fenwicktree.add(0, 0) 106 | assert fenwicktree.data == [1, 3, 3, 10, 5] 107 | 108 | def test_add_when_positive_floating_point_value_is_given( 109 | self, fenwicktree: FenwickTree 110 | ) -> None: 111 | ''' 112 | fenwicktree.add(p, x) is expected to add x to the p-th of the number 113 | sequence. 114 | 115 | GIVEN an initialized fenwicktree object 116 | WHEN add positive floating point value at arbitrary positions in the 117 | sequence 118 | THEN fenwicktree.data has a partial sum at any position in the sequence 119 | ''' 120 | 121 | fenwicktree.add(0, 1.5) 122 | assert fenwicktree.data == [1.5, 1.5, 0, 1.5, 0] 123 | 124 | def test_add_when_negative_floating_point_value_is_given( 125 | self, fenwicktree: FenwickTree 126 | ) -> None: 127 | ''' 128 | fenwicktree.add(p, x) is expected to add x to the p-th of the number 129 | sequence. 130 | 131 | GIVEN an initialized fenwicktree object 132 | WHEN add negative floating point value at arbitrary positions in the 133 | sequence 134 | THEN fenwicktree.data has a partial sum at any position in the sequence 135 | ''' 136 | 137 | fenwicktree.add(0, -1.5) 138 | assert fenwicktree.data == [-1.5, -1.5, 0, -1.5, 0] 139 | 140 | @pytest.mark.parametrize(( 141 | 'left', 'right', 'expected' 142 | ), [ 143 | (0, 5, 15), 144 | (0, 4, 10), 145 | (1, 4, 9), 146 | (1, 3, 5), 147 | (2, 2, 0), 148 | ]) 149 | def test_sum( 150 | self, fenwicktree: FenwickTree, left: int, right: int, expected: int 151 | ) -> None: 152 | ''' 153 | fenwicktree.sum(left, right) is expected to calculate the sum of the 154 | interval [left, right) 155 | 156 | GIVEN With arbitrary value(s) at arbitrary positions in the sequence 157 | added to an initialized fenwicktree object 158 | WHEN specify the interval [left, right) 159 | THEN returns the sum of interval [left, right) 160 | ''' 161 | 162 | for i in range(5): 163 | fenwicktree.add(i, i + 1) 164 | 165 | assert fenwicktree.sum(left, right) == expected 166 | 167 | @pytest.mark.parametrize(( 168 | 'left', 'right', 'expected' 169 | ), [ 170 | (0, 5, 17), 171 | (0, 4, 12), 172 | (0, 3, 8), 173 | (0, 2, 3), 174 | (0, 1, 1), 175 | (1, 4, 11), 176 | (1, 3, 7), 177 | (2, 2, 0), 178 | ]) 179 | def test_sum_when_additional_element_is_given( 180 | self, fenwicktree: FenwickTree, left: int, right: int, expected: int 181 | ) -> None: 182 | ''' 183 | fenwicktree.sum(left, right) is expected to calculate the sum of the 184 | interval [left, right) 185 | 186 | GIVEN With arbitrary value(s) at arbitrary positions in the sequence 187 | added to an initialized fenwicktree object 188 | WHEN specify the interval [left, right) after the additional element 189 | is given 190 | THEN returns the sum of interval [left, right) 191 | ''' 192 | 193 | for i in range(5): 194 | fenwicktree.add(i, i + 1) 195 | 196 | assert fenwicktree.sum(0, 5) == 15 197 | 198 | fenwicktree.add(2, 2) 199 | assert fenwicktree.data == [1, 3, 5, 12, 5] 200 | assert fenwicktree.sum(left, right) == expected 201 | 202 | @pytest.mark.parametrize(( 203 | 'p' 204 | ), [ 205 | -2, 206 | -1, 207 | 5, 208 | 6, 209 | ]) 210 | def test_add_failed_if_invalid_input_is_given( 211 | self, fenwicktree: FenwickTree, p: int 212 | ) -> None: 213 | ''' 214 | fenwicktree.add(p, x) is expected to be raised an AssertionError if an 215 | invalid input is given. 216 | 217 | GIVEN an initialized fenwicktree object 218 | WHEN an out-of-range index is given 219 | THEN raises an AssertionError 220 | ''' 221 | 222 | with pytest.raises(AssertionError): 223 | fenwicktree.add(p, None) 224 | 225 | @pytest.mark.parametrize(( 226 | 'left', 'right' 227 | ), [ 228 | (-2, 5), 229 | (-1, 5), 230 | (0, 6), 231 | (0, 7), 232 | (3, 2), 233 | (-1, 6), 234 | (-1, 7), 235 | ]) 236 | def test_sum_failed_if_invalid_input_is_given( 237 | self, fenwicktree: FenwickTree, left: int, right: int 238 | ) -> None: 239 | ''' 240 | fenwicktree.sum(left, right) is expected to be raised an AssertionError 241 | if an invalid input is given. 242 | 243 | GIVEN an initialized fenwicktree object 244 | WHEN an out-of-range index is given 245 | THEN raises an AssertionError 246 | ''' 247 | 248 | with pytest.raises(AssertionError): 249 | fenwicktree.sum(left, right) 250 | -------------------------------------------------------------------------------- /tests/test_internal_math.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from atcoder._math import _is_prime, _inv_gcd, _primitive_root 4 | 5 | 6 | class TestInternalMath: 7 | 8 | def test_is_prime(self) -> None: 9 | assert not _is_prime(-2) 10 | assert not _is_prime(-1) 11 | assert not _is_prime(121) 12 | assert not _is_prime(11 * 13) 13 | assert not _is_prime(701928443) 14 | assert _is_prime(998244353) 15 | assert not _is_prime(1_000_000_000) 16 | assert _is_prime(1_000_000_007) 17 | assert not _is_prime(1_000_000_008) 18 | assert _is_prime(1_000_000_009) 19 | 20 | for i in range(10000 + 1): 21 | assert _is_prime(i) == self._is_prime_naive(i) 22 | 23 | def _is_prime_naive(self, n: int) -> bool: 24 | from math import sqrt 25 | 26 | assert 0 <= n 27 | 28 | if (n == 0) or (n == 1): 29 | return False 30 | 31 | for i in range(2, int(sqrt(n)) + 1): 32 | if (n % i == 0): 33 | return False 34 | 35 | return True 36 | 37 | @pytest.mark.parametrize(( 38 | 'a', 'b', 'expected' 39 | ), [ 40 | (0, 1, 1), 41 | (0, 4, 4), 42 | (0, 7, 7), 43 | (2, 3, 1), 44 | (-2, 3, 1), 45 | (4, 6, 2), 46 | (-4, 6, 2), 47 | (13, 23, 1), 48 | (57, 81, 3), 49 | (12345, 67890, 15), 50 | (-3141592 * 6535, 3141592 * 8979, 3141592), 51 | ]) 52 | def test_inv_gcd(self, a: int, b: int, expected: int) -> None: 53 | s, m0 = _inv_gcd(a, b) 54 | assert s == expected 55 | assert (((m0 * a) % b + b) % b) == (s % b) 56 | 57 | def test_primitive_root(self) -> None: 58 | for m in range(2, 5000 + 1): 59 | if not _is_prime(m): 60 | continue 61 | 62 | n = _primitive_root(m) 63 | assert 1 <= n 64 | assert n < m 65 | 66 | x = 1 67 | 68 | for i in range(1, (m - 2) + 1): 69 | x = x * n % m 70 | # x == n ^ i 71 | assert x != 1 72 | 73 | x = x * n % m 74 | assert x == 1 75 | -------------------------------------------------------------------------------- /tests/test_math.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from typing import List, Tuple 3 | 4 | from atcoder.math import inv_mod, crt, floor_sum 5 | 6 | 7 | class TestMath: 8 | 9 | def test_inv_mod(self) -> None: 10 | ''' 11 | inv_mod(a, b) is expected to returns an integer y such that 0 <= y < m 12 | and xy ≡ 1 (mod m). 13 | 14 | GIVEN parameters a and b (>= 1), gcd(a, b) = 1 15 | WHEN inv_mod(a, b) is called 16 | THEN return an integer y such that 0 <= y < m and xy ≡ 1 (mod m) 17 | ''' 18 | 19 | from math import gcd 20 | 21 | for a in range(-100, 100 + 1): 22 | for b in range(1, 1000 + 1): 23 | if gcd(a % b, b) != 1: 24 | continue 25 | 26 | c = inv_mod(a, b) 27 | assert 0 <= c < b 28 | assert 1 % b == (((a * c) % b + b) % b) 29 | 30 | def test_inv_mod_when_returns_zero(self) -> None: 31 | ''' 32 | inv_mod(a, b) is expected to returns an integer y such that 0 <= y < m 33 | and xy ≡ 1 (mod m). 34 | 35 | GIVEN parameters a and b (= 1), gcd(a, b) = 1 36 | WHEN inv_mod(a, b) is called 37 | THEN return 0 38 | ''' 39 | 40 | assert inv_mod(0, 1) == 0 41 | 42 | for i in range(10): 43 | assert inv_mod(i, 1) == 0 44 | assert inv_mod(-i, 1) == 0 45 | 46 | @pytest.mark.parametrize(( 47 | 'r', 'm', 48 | 'expected' 49 | ), [ 50 | ([44, 23, 13], [13, 50, 22], 51 | (1773, 7150) 52 | ), 53 | ([12345, 67890, 99999], [13, 444321, 95318], 54 | (103333581255, 550573258014) 55 | ), 56 | ([0, 3, 4], [1, 9, 5], 57 | (39, 45) 58 | ), 59 | ([1, 2, 1], [2, 3, 2], 60 | (5, 6) 61 | ), 62 | ([], [], 63 | (0, 1) 64 | ), 65 | ]) 66 | def test_crt( 67 | self, r: List[int], m: List[int], expected: Tuple[int, int] 68 | ) -> None: 69 | ''' 70 | crt(r, m) is expected to return a pair of tuple value. 71 | 72 | GIVEN two arrays of the same size 73 | WHEN crt(r, m) is called 74 | THEN return a pair of tuple value. 75 | ''' 76 | 77 | assert crt(r, m) == expected 78 | 79 | def test_floor_sum(self) -> None: 80 | ''' 81 | floor_sum(n, m, a, b) is expected to return Σfloor((a * i + b) // m). 82 | 83 | GIVEN parameter n(>= 1), m(>= 1), a, b 84 | WHEN floor_sum(n, m, a, b) and self._floor_sum_naive(n, m, a, b) are 85 | called 86 | THEN the return values of the two methods match 87 | ''' 88 | 89 | value_max = 20 90 | 91 | for n in range(1, value_max + 1): 92 | for m in range(1, value_max + 1): 93 | for a in range(value_max + 1): 94 | for b in range(value_max + 1): 95 | assert floor_sum(n, m, a, b) \ 96 | == self._floor_sum_naive(n, m, a, b) 97 | 98 | def _floor_sum_naive(self, n: int, m: int, a: int, b: int) -> int: 99 | total = 0 100 | 101 | for i in range(n): 102 | total += (a * i + b) // m 103 | 104 | return total 105 | 106 | @pytest.mark.parametrize(( 107 | 'n', 'm', 'a', 'b', 'expected' 108 | ), [ 109 | (4, 10, 6, 3, 3), 110 | (6, 5, 4, 3, 13), 111 | (1, 1, 0, 0, 0), 112 | (31415, 92653, 58979, 32384, 314_095_480), 113 | (1000000000, 1000000000, 999999999, 999999999, 499999999500000000), 114 | ]) 115 | def test_floor_sum_using_acl_practice_contest( 116 | self, n: int, m: int, a: int, b: int, expected: int 117 | ) -> None: 118 | ''' 119 | Run floor_sum(n, m, a, b) using samples of ACL Practice Contest 120 | 121 | See: 122 | https://atcoder.jp/contests/practice2/tasks/practice2_c 123 | ''' 124 | assert floor_sum(n, m, a, b) == expected 125 | 126 | @pytest.mark.parametrize(( 127 | 'a', 'b' 128 | ), [ 129 | (2, -1), 130 | (2, 0), 131 | (271828, 0), 132 | (6, 3), 133 | (3, 6), 134 | (3141592, 1000000008), 135 | ]) 136 | def test_inv_mod_failed_if_invalid_input_is_given( 137 | self, a: int, b: int 138 | ) -> None: 139 | ''' 140 | inv_mod(a, b) is expected to be raised an AssertionError if an 141 | invalid input is given. 142 | 143 | GIVEN parameter a, b(< 1) or gcd(a, b) != 1 144 | WHEN inv_mod(a, b) is called 145 | THEN raises an AssertionError 146 | ''' 147 | 148 | with pytest.raises(AssertionError): 149 | inv_mod(a, b) 150 | 151 | @pytest.mark.parametrize(( 152 | 'r', 'm', 153 | ), [ 154 | ([], [1, 2]), 155 | ([1, 2], []), 156 | ([3], [1, 2]), 157 | ([1, 2], [1]), 158 | ([1, 2], [0, 0]), 159 | ([1, 2], [1, 0]), 160 | ([1, 2], [0, 1]), 161 | ([1, 2], [1, -1]), 162 | ([1, 2], [-1, -1]), 163 | ]) 164 | def test_crt_failed_if_invalid_input_is_given( 165 | self, r: List[int], m: List[int] 166 | ) -> None: 167 | ''' 168 | crt(r, m) is expected to be raised an AssertionError if an invalid 169 | input is given. 170 | 171 | GIVEN two arrays of different sizes or 172 | any one of m is less than or equal to zero 173 | WHEN crt(r, m) is called 174 | THEN raises an AssertionError 175 | ''' 176 | 177 | with pytest.raises(AssertionError): 178 | crt(r, m) 179 | 180 | @pytest.mark.parametrize(( 181 | 'n', 'm', 'a', 'b' 182 | ), [ 183 | (-1, 1, 0, 0), 184 | (0, 1, 0, 0), 185 | (1, 0, 0, 0), 186 | (1, -1, 0, 0), 187 | ]) 188 | def test_floor_sum_failed_if_invalid_input_is_given( 189 | self, n: int, m: int, a: int, b: int 190 | ) -> None: 191 | ''' 192 | floor_sum(n, m, a, b) is expected to be raised an AssertionError if an 193 | invalid input is given. 194 | 195 | GIVEN parameter n(< 1), m(< 1), a, b 196 | WHEN floor_sum(n, m, a, b) is called 197 | THEN raises an AssertionError 198 | ''' 199 | 200 | with pytest.raises(AssertionError): 201 | floor_sum(n, m, a, b) 202 | --------------------------------------------------------------------------------