Loading [MathJax]/jax/output/CommonHTML/jax.js

AtCoder Regular Contest 196 (Div. 1) A,B問題メモ

A - Adjacent Delete

問題文

  • 長さ N の数列 A=(A1,A2,,AN) が与えられます。
  • あなたはこの数列の隣接する 2 数を選びどちらもこの数列から削除する、という操作を数列の長さが 1 以下になるまで繰り返します。
  • 一度の操作で得られるスコアは選んだ 2 数の差の絶対値です。
  • 得られるスコアの合計としてありうる最大値を求めてください。

制約

  • 2N3×105
  • 1Ai109
  • 入力はすべて整数

解法

分かってみれば単純なんだけどね。本番中は違う方針に走って時間かかっちゃった。

K=N2 とする。操作は K 回おこなうことになる。

A の大きい方から K 要素の多重集合を Sl、小さい方から K 要素の多重集合を Ss とする。

仮に、隣接でなくても自由にペアが作れるとした場合、 達成できる最大値は sum(Sl)sum(Ss) である。
この時「Sl から1要素と Ss から1要素をペアにする」ことを守れば、具体的なペアの組み方は関係ない。

N が偶数の時、この最大値は必ず達成できる。
なぜなら、常に「Sl の要素と Ss の要素が隣接する箇所」は存在するから。それを選び続ければいい。

奇数の場合が問題だが、これも「残す1要素」を固定すれば、左右に分割した長さ偶数の2区間それぞれで同じことが言える。
以下の2つがわかれば、奇数の i に対して Li1+RNi が、Ai を残すときの最大値となる。

  • Li:= 先頭 i 要素だけで Sl,Ss を考えたときの、sum(Sl)sum(Ss)(偶数の i に対してのみ定義)
  • Ri:= 末尾 i 要素だけで Sl,Ss を考えたときの、sum(Sl)sum(Ss)(偶数の i に対してのみ定義)

Ss,Sl をそれぞれ heapq などで実装して、 先頭から常に2つの要素数が均一になるように調整しながら Ai を加えていけば、Li を作れる。
末尾からも同様に Ri を作れば、答えが求められる。

Python3

B - Torus Loop

問題文

  • HW 列のグリッドがあり、各マス Si,j には以下の2種類のタイルのいずれかが置かれています。
    • 種類 A:タイルの表面に、隣接する 2 辺の中点どうしを結ぶ線分が一本描かれている
    • 種類 B:タイルの表面に、向かい合う 2 辺の中点どうしを結ぶ線分が一本描かれている
    • (具体的な絵は問題ページ参照)
  • タイルは自由に回転可能としたとき、タイルを配置する方法の数は、A のタイルの数 a、B のタイルの数 b を用いて、4a×2b 通りあります。
  • このうち、グリッドをトーラスとして見たときにタイルに描かれた線分が行き止まりを持たないようにタイルを配置する方法の数を 998244353 で割ったあまりを出力してください。
  • T 個のテストケースが与えられるので、それぞれについて解いてください。

制約

  • 1T105
  • 2H,W
  • HW106
  • Si(0iH1) は A と B のみからなる長さ W の文字列
  • すべてのテストケースにわたる HW の総和は 106 以下
  • T,H,W は整数

解法

ペンシルパズルなんかを解くときによくある考え方だが、 「ここには線が通る」という情報と同じくらい、「線が通らない」という情報も重要である。

┼  ┼  ┼  ┼  ┼  ┼    この、┼ に挟まれたタテヨコの各隙間に、
  B  A  A  B  B      「線が通る」か「通らない」かを(矛盾なく)決めれば、
┼  ┼  ┼  ┼  ┼  ┼    タイルの向きは一意に決まる。
  A  A  B  A  A
┼  ┼  ┼  ┼  ┼  ┼    タイルの向きの代わりに、各隙間に
  A  B  A  A  A      「線が通る」「通らない」を決めることを考える。
┼  ┼  ┼  ┼  ┼  ┼    ただし、一番上の行と一番下の行、一番左の列と一番右の列は、
                          トーラスなので一致している必要がある。

左上のBに横向きに線を引くと仮定すると、以下まで連鎖的に決まる。

┼×┼  ┼  ┼×┼×┼
━B━A×A━B━B━
┼×┼  ┼  ┼×┼×┼
  A  A  B  A  A
┼┃┼  ┼  ┼┃┼┃┼
  A  B  A  A  A  
┼×┼  ┼  ┼×┼×┼

縦向きに線を引くと仮定すると、全てが反転した形で同じ箇所が以下のように決まる。

┼┃┼  ┼  ┼┃┼┃┼
×B×A━A×B×B×
┼┃┼  ┼  ┼┃┼┃┼
  A  A  B  A  A
┼×┼  ┼  ┼×┼×┼
  A  B  A  A  A  
┼┃┼  ┼  ┼┃┼┃┼

隙間に線が通るか通らないかに着目したとき、各タイルは以下の性質を持つ。

  • タイルAの性質
    • 左に線が通る(━)ことが決まったら、右は通らない(×)ことが決まる。
    • 左に線が通らない(×)ことが決まったら、右は通ること(━)が決まる。
    • 左右が決まっても、上下は決まらない。
  • タイルBの性質
    • 左に線が通る(━)ことが決まったら、右も通り(━)、上下は通らない(×)ことが決まる。
    • 左に線が通らない(×)ことが決まったら、右も通らず(×)、上下は通る(┃)ことが決まる。
  • ※それぞれ、左右や上下を入れ替えても同じことが言える。

つまり、ある行における1つの隙間を「×」か「━」か決めれば、以下のことが発生する。

  • 同じ行の隙間は全て「×」か「━」か決まる
  • その行にBがあると、Bがある列も全て「×」か「┃」か決まる。
  • さらにその列に他のBがあると、その行も全て「×」か「━」か決まる。
  • …というのが連鎖的に繰り返される。

ここで、矛盾するケースが2つある。

  • Aが奇数個あるような行または列が1つでもある場合
    • 1つの行・列内で、Aによる━/×の反転はちょうど偶数回発生しないと、1周したときに合わなくなる。
  • Bが矛盾する場合
┼┃┼  ┼×┼…    左上のBを仮定して通る通らないを決めていった結果、
×B×A━B━      ここのBが矛盾
┼┃┼  ┼×┼…    │
×B×A━A        │
┼┃┼  ┼┃┼…    │
×B×A━B?    ←┘
┼┃┼  ┼?┼…
:  :  :  :

同じ行・列内にある2つのBは、間に挟まれるAの個数によって、一方の向きが決まったとき、もう一方が同じ向きか違う向きか決まる。 この時、行からの制約と、列からの制約が、矛盾することがある。
二部グラフ判定やポテンシャル付きUnionFindなどで、判定をおこなえる。

矛盾が無い場合、各行・各列を1頂点とした H+W 頂点のグラフを考える。
(i,j) がBだったとすると、行 i と列 j を連結にしていく。

連結になった行・列は、どこか1箇所の通る通らないが決まれば全て決まる。
一方、連結でない行・列同士は独立に決められる。

最終的な連結成分の個数を d とすると、2d 通りの決め方がある。

Python3


考察の最初の方にBの矛盾条件に気付いていたはずなのに、詰めていくうちにいつの間にかどっか行ってた。ううむ。

programming_algorithm/contest_history/atcoder/2025/0406_arc196.txt · 最終更新: 2025/04/06 by ikatakos
CC Attribution 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0