結果

問題 No.2910 単体ホモロジー入門
ユーザー osada-yumosada-yum
提出日時 2024-11-04 20:21:20
言語 Fortran
(gFortran 13.2.0)
結果
AC  
実行時間 2 ms / 2,000 ms
コード長 17,360 bytes
コンパイル時間 993 ms
コンパイル使用メモリ 45,364 KB
実行使用メモリ 6,820 KB
最終ジャッジ日時 2024-11-04 20:21:24
合計ジャッジ時間 2,747 ms
ジャッジサーバーID
(参考情報)
judge1 / judge2
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 1 ms
6,816 KB
testcase_01 AC 2 ms
6,820 KB
testcase_02 AC 1 ms
6,816 KB
testcase_03 AC 1 ms
6,816 KB
testcase_04 AC 2 ms
6,816 KB
testcase_05 AC 1 ms
6,816 KB
testcase_06 AC 2 ms
6,816 KB
testcase_07 AC 1 ms
6,820 KB
testcase_08 AC 2 ms
6,820 KB
testcase_09 AC 1 ms
6,816 KB
testcase_10 AC 1 ms
6,816 KB
testcase_11 AC 1 ms
6,816 KB
testcase_12 AC 2 ms
6,816 KB
testcase_13 AC 1 ms
6,820 KB
testcase_14 AC 1 ms
6,820 KB
testcase_15 AC 1 ms
6,816 KB
testcase_16 AC 1 ms
6,820 KB
testcase_17 AC 2 ms
6,816 KB
testcase_18 AC 2 ms
6,816 KB
testcase_19 AC 1 ms
6,820 KB
testcase_20 AC 2 ms
6,820 KB
testcase_21 AC 1 ms
6,816 KB
testcase_22 AC 1 ms
6,816 KB
testcase_23 AC 1 ms
6,820 KB
testcase_24 AC 1 ms
6,820 KB
testcase_25 AC 1 ms
6,816 KB
testcase_26 AC 1 ms
6,820 KB
testcase_27 AC 1 ms
6,820 KB
testcase_28 AC 1 ms
6,816 KB
testcase_29 AC 1 ms
6,820 KB
testcase_30 AC 1 ms
6,816 KB
testcase_31 AC 1 ms
6,816 KB
testcase_32 AC 1 ms
6,816 KB
testcase_33 AC 1 ms
6,820 KB
testcase_34 AC 1 ms
6,820 KB
testcase_35 AC 1 ms
6,816 KB
testcase_36 AC 2 ms
6,816 KB
testcase_37 AC 1 ms
6,816 KB
testcase_38 AC 2 ms
6,816 KB
testcase_39 AC 1 ms
6,820 KB
testcase_40 AC 1 ms
6,820 KB
testcase_41 AC 2 ms
6,816 KB
testcase_42 AC 1 ms
6,820 KB
testcase_43 AC 1 ms
6,820 KB
testcase_44 AC 1 ms
6,816 KB
testcase_45 AC 1 ms
6,820 KB
testcase_46 AC 1 ms
6,820 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

!> This file was processed by `fypp`.
!> Today's fortune: "Happy TLE", really OK?
!> ランダムウォーク猿「'ソート' で はっぴー.」
!> ギャンブラー猿「AtCoder はギャンブルだ.」

module merge_sort_m
  use, intrinsic :: iso_fortran_env
  !> maybe use module.
  implicit none
  private
  public :: merge_sort
  interface merge_sort
     module procedure :: merge_sort_int32
  end interface merge_sort
contains
  pure subroutine merge_sort_int32(arr, indices, reverse)
    integer(int32), intent(inout) :: arr(:)
    integer(int32), intent(inout), optional :: indices(:)
    logical, intent(in), optional :: reverse
    integer(int32), allocatable :: idx(:)
    integer(int32) :: n
    integer(int32) :: i
    n = size(arr)
    allocate(idx, source = [(i, i = 1, n)])
    if (present(reverse)) then
       if (reverse) then
          call merge_sort_sub_descending(n, arr, idx)
          if (present(indices)) &
               indices(:) = idx(:)
          return
       end if
    end if
    call merge_sort_sub_ascending(n, arr, idx)
    if (present(indices)) &
         indices(:) = idx(:)
    return
  contains
    pure subroutine merge_sort_sub_ascending(n, arr, idx)
      integer(int32), intent(in) :: n
      integer(int32), intent(inout) :: arr(n)
      integer(int32), intent(inout) :: idx(n)
      integer(int32) :: width
      integer(int32) :: i, l, r
      width = 2
      do while (width <= 2 * n)
         do i = 1, n, width
            if (i + width / 2 > n) exit
            l = i
            r = min(n, i + width - 1)
            call merge_sort_int32_merge_with_key_ascending(r - l + 1, width/2, arr(l:r), idx(l:r))
         end do
         width = width * 2
      end do
    end subroutine merge_sort_sub_ascending
    pure subroutine merge_sort_sub_descending(n, arr, idx)
      integer(int32), intent(in) :: n
      integer(int32), intent(inout) :: arr(n)
      integer(int32), intent(inout) :: idx(n)
      integer(int32) :: width
      integer(int32) :: i, l, r
      width = 2
      do while (width <= 2 * n)
         do i = 1, n, width
            if (i + width / 2 > n) exit
            l = i
            r = min(n, i + width - 1)
            call merge_sort_int32_merge_with_key_descending(r - l + 1, width/2, arr(l:r), idx(l:r))
         end do
         width = width * 2
      end do
    end subroutine merge_sort_sub_descending
  end subroutine merge_sort_int32
  pure subroutine merge_sort_int32_merge_with_key_ascending(n, nl, arr, indices)
    integer(int32), intent(in) :: n, nl
    integer(int32), intent(inout) :: arr(n)
    integer(int32), intent(inout) :: indices(n)
    integer(int32) :: idx_left(1:nl), idx_right(nl + 1:n)
    integer(int32) :: idx(n)
    integer(int32) :: i, j, k
    if (n == 1) return
    idx_left(1:nl) = [(i, i = 1, nl)]
    idx_right(nl + 1:n) = [(i, i = nl + 1, n)]
    i = 1
    j = nl + 1
    do k = 1, n
       if (arr(i) <= arr(j)) then
          idx(k) = idx_left(i)
          i = i + 1
       else
          idx(k) = idx_right(j)
          j = j + 1
       end if
       if (i > nl) then
          idx(k + 1:n) = idx_right(j:n)
          exit
       else if (j > n) then
          idx(k + 1:n) = idx_left(i:nl)
          exit
       end if
    end do
    arr(:) = arr(idx)
    indices(:) = indices(idx)
  end subroutine merge_sort_int32_merge_with_key_ascending
  pure subroutine merge_sort_int32_merge_with_key_descending(n, nl, arr, indices)
    integer(int32), intent(in) :: n, nl
    integer(int32), intent(inout) :: arr(n)
    integer(int32), intent(inout) :: indices(n)
    integer(int32) :: idx_left(1:nl), idx_right(nl + 1:n)
    integer(int32) :: idx(n)
    integer(int32) :: i, j, k
    if (n == 1) return
    idx_left(1:nl) = [(i, i = 1, nl)]
    idx_right(nl + 1:n) = [(i, i = nl + 1, n)]
    i = 1
    j = nl + 1
    do k = 1, n
       if (arr(i) >= arr(j)) then
          idx(k) = idx_left(i)
          i = i + 1
       else
          idx(k) = idx_right(j)
          j = j + 1
       end if
       if (i > nl) then
          idx(k + 1:n) = idx_right(j:n)
          exit
       else if (j > n) then
          idx(k + 1:n) = idx_left(i:nl)
          exit
       end if
    end do
    arr(:) = arr(idx)
    indices(:) = indices(idx)
  end subroutine merge_sort_int32_merge_with_key_descending
end module merge_sort_m

module unwrapped_vector_m
  use, intrinsic :: iso_fortran_env
  !> maybe use module.
  implicit none
  private
  public :: unwrapped_vector_int32
  type :: unwrapped_vector_int32
     private
     integer(int32) :: size_ = 0, capa_ = 0
     integer(int32), allocatable, public :: arr_(:)
   contains
     procedure, pass :: init      => init_unwrapped_vector_int32
     procedure, pass :: with_capacity => with_capacity_unwrapped_vector_int32
     procedure, pass :: push_back_unwrapped_vector_int32, &
          push_back_array_unwrapped_vector_int32
     generic         :: push_back => push_back_unwrapped_vector_int32, &
          push_back_array_unwrapped_vector_int32
     procedure, pass :: pop_back  => pop_back_unwrapped_vector_int32
     procedure, pass :: back      => back_unwrapped_vector_int32
     procedure, pass :: size   => size_unwrapped_vector_int32
     procedure, pass :: resize => resize_unwrapped_vector_int32
     procedure, pass :: lower_bound => lower_bound_unwrapped_vector_int32
     procedure, pass :: upper_bound => upper_bound_unwrapped_vector_int32
  end type unwrapped_vector_int32
  interface unwrapped_vector_int32
     module procedure :: construct_unwrapped_vector_int32_by_size, &
          construct_unwrapped_vector_int32_by_arr, &
          construct_unwrapped_vector_int32_by_init_val
  end interface unwrapped_vector_int32

! #:block once_block(name = f"unwrapped_vector{getvar('UNWRAPPED_VECTOR_MODULENAME_SUFFIX', '')}")
  public :: compare, operator(<), operator(<=), operator(>), operator(>=), operator(==), operator(/=)


  interface compare
     module procedure :: compare_unwrapped_vector_int32
  end interface compare
  interface operator(<)
     module procedure :: less_unwrapped_vector_int32
  end interface operator(<)
  interface operator(<=)
     module procedure :: less_equal_unwrapped_vector_int32
  end interface operator(<=)
  interface operator(>)
     module procedure :: greater_unwrapped_vector_int32
  end interface operator(>)
  interface operator(>=)
     module procedure :: greater_equal_unwrapped_vector_int32
  end interface operator(>=)
  interface operator(==)
     module procedure :: equal_unwrapped_vector_int32
  end interface operator(==)
  interface operator(/=)
     module procedure :: not_equal_unwrapped_vector_int32
  end interface operator(/=)
contains
  pure function construct_unwrapped_vector_int32_by_size(size) result(res)
    type(unwrapped_vector_int32) :: res
    integer(int32), intent(in) :: size
    call res%init(size)
  end function construct_unwrapped_vector_int32_by_size
  pure function construct_unwrapped_vector_int32_by_arr(arr) result(res)
    type(unwrapped_vector_int32) :: res
    integer(int32), intent(in) :: arr(:)
    integer(int32) :: n
    n = size(arr)
    call res%init(n)
    res%arr_(1:n) = arr(1:n)
  end function construct_unwrapped_vector_int32_by_arr
  pure function construct_unwrapped_vector_int32_by_init_val(size, val) result(res)
    type(unwrapped_vector_int32) :: res
    integer(int32), intent(in) :: size
    integer(int32), intent(in) :: val
    call res%init(size)
    res%arr_(1:size) = val
  end function construct_unwrapped_vector_int32_by_init_val
  pure subroutine init_unwrapped_vector_int32(this, n)
    class(unwrapped_vector_int32), intent(inout) :: this
    integer(int32), intent(in) :: n
    if (.not. allocated(this%arr_)) then
       allocate(this%arr_(n))
       this%size_ = n
       this%capa_ = n
    end if
  end subroutine init_unwrapped_vector_int32
  pure subroutine with_capacity_unwrapped_vector_int32(this, n)
    class(unwrapped_vector_int32), intent(inout) :: this
    integer(int32), intent(in) :: n
    if (.not. allocated(this%arr_)) then
       allocate(this%arr_(n))
       this%size_ = 0
       this%capa_ = n
    end if
  end subroutine with_capacity_unwrapped_vector_int32
  pure subroutine push_back_unwrapped_vector_int32(this, val)
    class(unwrapped_vector_int32), intent(inout) :: this
    integer(int32), intent(in) :: val
    if (.not. allocated(this%arr_)) call this%with_capacity(1)
    if (this%size_ == this%capa_) then
       call this%resize(2*this%capa_)
    end if
    this%size_ = this%size_ + 1
    this%arr_(this%size_) = val
  end subroutine push_back_unwrapped_vector_int32
  pure subroutine push_back_array_unwrapped_vector_int32(this, arr)
    class(unwrapped_vector_int32), intent(inout) :: this
    integer(int32), intent(in) :: arr(:)
    integer(int32) :: s
    s = size(arr)
    if (.not. allocated(this%arr_)) &
         call this%with_capacity(s)
    if (this%size_ + s > this%capa_) then
       call this%resize(this%size_ + s)
    end if
    this%arr_(this%size_+1:this%size_+s) = arr(:)
    this%size_ = this%size_ + s
  end subroutine push_back_array_unwrapped_vector_int32
  pure subroutine pop_back_unwrapped_vector_int32(this)
    class(unwrapped_vector_int32), intent(inout) :: this
    this%size_ = this%size_ - 1
  end subroutine pop_back_unwrapped_vector_int32
  pure integer(int32) function back_unwrapped_vector_int32(this) result(res)
    class(unwrapped_vector_int32), intent(in) :: this
    res = this%arr_(this%size_)
  end function back_unwrapped_vector_int32
  pure integer(int32) function size_unwrapped_vector_int32(this) result(res)
    class(unwrapped_vector_int32), intent(in) :: this
    res = this%size_
  end function size_unwrapped_vector_int32
  pure subroutine resize_unwrapped_vector_int32(this, resize)
    class(unwrapped_vector_int32), intent(inout) :: this
    integer(int32), intent(in) :: resize
    integer(int32), allocatable :: tmp(:)
    if (.not. allocated(this%arr_)) then
       call this%init(resize)
       return
    end if
    if (resize < 1) then
       this%size_ = 0
       allocate(tmp(1))
       call move_alloc(from = tmp, to = this%arr_)
       this%capa_ = 1
    else
       if (this%capa_ == resize) return
       allocate(tmp(resize))
       this%size_ = min(this%size_, resize)
       tmp(1:this%size_) = this%arr_(1:this%size_)
       call move_alloc(from = tmp, to = this%arr_)
       this%capa_ = resize
    end if
  end subroutine resize_unwrapped_vector_int32
  pure integer(int32) function lower_bound_unwrapped_vector_int32(this, val) result(res)
    class(unwrapped_vector_int32), intent(in) :: this
    integer(int32), intent(in) :: val
    res = lower_bound(this%arr_(1:this%size()), val)
  contains
    pure integer(int32) function lower_bound(arr, val) result(res)
      integer(int32), intent(in) :: arr(:)
      integer(int32), intent(in) :: val
      integer(int32) :: p, q, r
      p = 1
      r = size(arr)
      if (r == 0) then
         res = r + 1; return
      else if (arr(p) >= val) then
         res = p; return
      else if (arr(r) < val) then
         res = r + 1; return
      end if
      !> invariant conditions:
      !> arr(p) < v.
      !> arr(r) >= v.
      do while (p + 1 < r)
         q = (p + r)/ 2
         if (arr(q) >= val) then
            r = q
         else !> arr(q) < val
            p = q
         end if
      end do
      res = r
    end function lower_bound
  end function lower_bound_unwrapped_vector_int32
  pure integer(int32) function upper_bound_unwrapped_vector_int32(this, val) result(res)
    class(unwrapped_vector_int32), intent(in) :: this
    integer(int32), intent(in) :: val
    res = upper_bound(this%arr_(1:this%size()), val)
  contains
    pure integer(int32) function upper_bound(arr, val) result(res)
      integer(int32), intent(in) :: arr(:)
      integer(int32), intent(in) :: val
      integer(int32) :: p, q, r
      p = 1
      r = size(arr)
      if (arr(p) > val) then
         res = p; return
      else if (arr(r) <= val) then
         res = r + 1; return
      end if
      !> invariant conditions:
      !> arr(p) <= v.
      !> arr(r) > v.
      do while (p + 1 < r)
         q = (p + r)/ 2
         if (arr(q) > val) then
            r = q
         else !> arr(q) < val
            p = q
         end if
      end do
      res = r
    end function upper_bound
  end function upper_bound_unwrapped_vector_int32
  pure integer(int32) function compare_unwrapped_vector_int32(lhs, rhs) result(res)
    type(unwrapped_vector_int32), intent(in) :: lhs, rhs
    integer(int32) :: i
    associate(ls => lhs%size(), rs => rhs%size())
      if (ls == 0 .and. rs == 0) then
         res = 0; return
      else if (ls == 0) then
         res = -1; return
      else if (rs == 0) then
         res = +1; return
      end if
      do i = 1, min(ls, rs)
         if (lhs%arr_(i) < rhs%arr_(i)) then
            res = -1; return
         else if (lhs%arr_(i) > rhs%arr_(i)) then
            res = +1; return
         end if
      end do
      if (ls == rs) then
         res = 0
      else if (ls < rs) then
         res = -1
      else
         res = +1
      end if
    end associate
  end function compare_unwrapped_vector_int32
  !> less_unwrapped_vector_int32: Compare the first elements.
  !> Compare the second elements if the first elements are same.
  pure logical function less_unwrapped_vector_int32(lhs, rhs) result(res)
    type(unwrapped_vector_int32), intent(in) :: lhs, rhs
    res = compare(lhs, rhs) < 0
  end function less_unwrapped_vector_int32
  pure logical function less_equal_unwrapped_vector_int32(lhs, rhs) result(res)
    type(unwrapped_vector_int32), intent(in) :: lhs, rhs
    res = compare(lhs, rhs) <= 0
  end function less_equal_unwrapped_vector_int32
  pure logical function greater_unwrapped_vector_int32(lhs, rhs) result(res)
    type(unwrapped_vector_int32), intent(in) :: lhs, rhs
    res = compare(lhs, rhs) > 0
  end function greater_unwrapped_vector_int32
  pure logical function greater_equal_unwrapped_vector_int32(lhs, rhs) result(res)
    type(unwrapped_vector_int32), intent(in) :: lhs, rhs
    res = compare(lhs, rhs) >= 0
  end function greater_equal_unwrapped_vector_int32
  pure logical function equal_unwrapped_vector_int32(lhs, rhs) result(res)
    type(unwrapped_vector_int32), intent(in) :: lhs, rhs
    res = compare(lhs, rhs) == 0
  end function equal_unwrapped_vector_int32
  pure logical function not_equal_unwrapped_vector_int32(lhs, rhs) result(res)
    type(unwrapped_vector_int32), intent(in) :: lhs, rhs
    res = compare(lhs, rhs) /= 0
  end function not_equal_unwrapped_vector_int32
end module unwrapped_vector_m
program f902910
  use, intrinsic :: iso_fortran_env
  !> auto use module
  use merge_sort_m
  use unwrapped_vector_m
  use merge_sort_m
  use unwrapped_vector_m, only: vec_i32 => unwrapped_vector_int32
  implicit none
  integer(int32) :: n, m
  logical, allocatable :: g(:, :)
  integer(int32) :: i
  read(input_unit, *) n, m
  allocate(g(0:n-1, 0:n-1), source = .false.)
  do i = 1, m
     block
       integer(int32) :: a, b
       read(input_unit, *) a, b
       g(a, b) = .true.
       g(b, a) = .true.
     end block
  end do
  block
    integer(int32), parameter :: nvs = 3
    integer(int32) :: vs(nvs)
    logical :: is_duplicated, visited(0:n-1)
    type(vec_i32) :: path
    read(input_unit, *) vs(:)
    is_duplicated = .false.
    do i = 1, nvs
       ! write(error_unit, *) i, count(vs(i) == vs(:))
       if (count(vs(i) == vs(:)) > 1) &
            & is_duplicated = .true.
    end do
    call merge_sort(vs)
    do i = 0, n - 1
       path = vec_i32()
       visited(:) = .false.
       call search_cycle_dfs(n, g, visited, i, i, -1, nvs, vs, path, is_duplicated)
    end do
    write(output_unit, '(a)') "No"
  end block
contains
  impure recursive subroutine search_cycle_dfs(n, g, visited, first_v, v, p, nvs, vs, path, is_duplicated)
    integer(int32), intent(in) :: n, first_v, v, p
    integer(int32), intent(in) :: nvs, vs(nvs)
    logical, intent(in) :: g(0:n-1, 0:n-1), is_duplicated
    logical, intent(inout) :: visited(0:n-1)
    type(vec_i32), intent(inout) :: path
    integer(int32) :: i
    ! write(error_unit, *) v, p
    if (p /= -1 .and. first_v == v) then
       ! write(error_unit, *) nvs, vs(:)
       ! write(error_unit, *) path%size(), path%arr_(1:path%size())
       ! write(error_unit, *) is_duplicated
       if (is_duplicated) then !> 重複ありなら, 閉路がある時点で, 一致しない閉路となる.
          write(output_unit, '(a)') "Yes"
          stop
       end if
       !> .not. is_duplicated
       if (path%size() /= nvs) then !> サイズがnvでないなら一致しない.
          write(output_unit, '(a)') "Yes"
          stop
       end if
       call merge_sort(path%arr_(1:path%size()))
       if (all(vs(:) == path%arr_(1:path%size()))) return !> 一致している.
       !> path は vs と一致していない閉路.
       write(output_unit, '(a)') "Yes"
       stop
    end if
    if (visited(v)) return
    visited(v) = .true.
    do i = 0, n - 1
       if (.not. g(v, i)) cycle
       if (i == p) cycle
       call path%push_back(v)
       call search_cycle_dfs(n, g, visited, first_v, i, v, nvs, vs, path, is_duplicated)
       call path%pop_back()
    end do
    visited(v) = .false.
  end subroutine search_cycle_dfs
end program f902910
0