Codeforces Round #576 (Div. 2)

寝坊した。。。まぢムリ…

 

バチャしたから書くお

 

 

codeforces.com

 

 

A - City Day

問題:N日の降水量が与えられる。そんなに雨が降ってない日かつ最も早い日を求めよ。そんなに雨が降ってない日:d-x<=j<d,d<j<=d+yを満たすjについてad<ajを満たすd

 

 

感想、考察:

数式で条件を与えてくれたのでわかりやすいですね。

ただ、d-xが0以下になったり、index outのときどうするのかがわかりづらかったです

 

と思ったらサンプルの下に書いてあったので楽でした

 

解法としては、全てのdでindex outをしないように-x~+yまで(dと一致しないところ)を、全探索すればよいです。

 

 

 


B - Water Lily

問題:Lilyの花が水面高さHに浮いている。中心からLだけ動かしたら丁度水面に接した。茎の長さを一定としたとき、生えている深さ求めよ。

 

Lilyって何だろうと思ったけどユリらしいです。百合ですね。Lily Whiteですね。

 

 

感想、考察:

図が書いてあるのでかなりわかりやすかったです。

 

なんだか中学校あたりでよく見たような図が

 

茎の長さをr、深さをxとします。

・H+x=r

・L^2+x^2=r^2(三平方の定理)

 

この連立方程式を解くとうまい具合に一次になります

L^2 = H^2 + 2Hx

これを解いて出力すればよいです

 

 


C -MP3

問題:N個の非負整数Aiが与えられる。K種類としたとき、使用するメモリは、(log2(K)の切り上げ)*N bitsである。ある整数l、r(l<=r)を決めて、全てのAiを、l未満ならlに、rより大きければrにする操作が行える。使用メモリ量をIbytes以下にせよ

ただし1bytes=8bitsである。

 

考察:

要するにl未満、rより大きい範囲の整数を消して、全体の種類数(最小1種類以上)を減らすという問題です。

 

ここで、l、rの指定は1回で十分です。2回目で範囲を狭くするなら元から狭くしておけば良いし、広くしても対象の整数はありません。

 

 

次にIの制約を考えましょう。

log2(K)の切り上げを取っているので、2^(x-1)+1~2^xは同じ値になります。

したがってK=2^xとして

nx<=8Iを満たすxを考えればよいです。単位変換してます。

これは当然x=8I//nです。

 

 

あとはl、rに対する種類数を求められれば良いです

単純に考えるとai<=10^9よりその二乗の時間がかかってしまいそうです

 

あらかじめ整数を種類ごとに数えて昇順にしておきましょう。(mapなどを使います)

こうすることで高々N種類になりました。

 

そしてK種類取れればよいのでK種類ずつスライドして見ていけばよいです。尺取り法などを使いO(N)で解くことができます

 

 

 


D -Welfare State

問題:N人の市民の資産aiが与えられる。Q個のクエリが与えられる

クエリ1:pさんの資産をxとする

クエリ2:資産がx未満の人全員を、xにする

全てのクエリを終えたときの全員の資産を求めよ

 

 

 

考察:

まずクエリ1がx以下のときは変化しないとか、x減らすとかじゃないことに感謝します。

 

クエリ1があったとき、その前のクエリに全く関係なくpさんの資産をxにすることが可能です。

つまりクエリ1だけ考えれば、各人の最後のクエリ1だけ見ればよいです。

 

 

次にあるiさんは、最後のクエリ1のあとどのように資産を変化させるでしょうか。

これは最後のクエリ1以降のクエリ2の最大値、または最後のクエリ1の値になります。

 

 

これは簡単に示すことができて、まず最後のクエリ1の値をx0、それ以降のクエリ2の値をx1、x2…xkとします

x1~xkで資産が減ることはないので大きいときだけ更新されます。

 

 

はいセグ木ペタンコー^^

 

区間の最大値を取得は雑にセグ木でいいと思います。

クエリ2の値だけ格納していきます。

それとは別に各人をクエリ1の値で更新し、最後の更新のindexを持っておきます

O((N+Q)logQ)です

 

 

 

 

別解?:

実装してないので不確かです。

セグ木を使わなくても、クエリを読み終わった後、後ろからクエリを読めばO(N+Q)解ける気がしました。

 

後ろから見て

クエリ2:いま保証されているxmを更新

クエリ1:pさんの値をそのクエリのxiとxmのmaxで確定。もしその前に確定していれば処理しない。

 

最後に初期値をクエリ1としてN人分見て出力すれば良さそう

たぶんこっちが想定解ですね。早いし。

 

 

 

 


E -Matching vs Independent Set

問題:頂点3N個、辺M個の単純グラフが与えられる。

1:端点を共有しないN個の辺

2:どの2点も連結でないN個の頂点

このどちらかは存在するか。存在すれば求めよ

クエリ問題でありT個のグラフが与えられる

 

考察:

1だけだったら二部マッチング問題にできそう

ただ計算量的にキツイ

 

2はよくわからん。グラフの色塗りっぽくするのか。

 

答え見て勉強しよう。

 

 

 

 

解説ACしたので以下追記

E -Matching vs Independent Set

直感的に1が2N個の頂点、2がN個の頂点を必要とするとわかります

 

解説によると、順序関係なく貪欲に追加していけばよいそうです

 

端点が未使用なら枝を追加。最後に枝がN本以上あるなら枝を出力。ないなら未使用の頂点をN個出力でOKです

 

 

高速化:

上の貪欲ではTLで弾かれてしまいました。

調べたところcin高速化というテクニックがあるそうです

 

そもそも標準入出力に時間がかかっているということで

  1. ios::sync_with_stdio(false);
  2. cin.tie(nullptr);

これを書いておくとcinが早くなるらしいです

また、endlの代わりに'\n'を使っても早くなるそうです。

 

両方使用で296ms、cinだけで623msでした。結構変わりますね。

インタラクティブ問題ではまた注意する必要があるそうです。あんまり使わないほうが良いかも

 

printf、scanfについて。こっちのほうが速いらしいですけど、vscode上では動かない?コンパイラの関係?かなんかで怪しいのでしばらくは使わないと思います

 

 

 

 

F - Rectangle Painting 1

問題:白黒の正方形グリッドが与えられる。あるh*wの任意の範囲を白に塗るコストはmax(h,w)である。すべて白にする最小コストを求めよ

 

考察:

再帰DPっぽい。Nが小さいし。

正方形で塗るのが最適だから正方形分割かと思ったけど無理そう

 

 

解説:

DP[x1][x2][y1][y2]:長方形(x1,x2](y1,y2]の区間を塗るための最小コスト

これを再帰DPで調べる

 

解説と区間の取り方がちょっと違います。なんか適当に二次元累積和書いてたらそうなっちゃったからで、特に理由はないです

 

まず、考える範囲に黒のマスがない場合、コストは0です。

これは二次元累積和をあらかじめ計算しておくことで、O(1)でわかります

 

次に再帰を考えます。ここで苦労しました

 

誤答:縦横、x3、y3で分割する

正答:縦x3で分割。横y3で分割。

 

一見同じようなことをしてるように見えますが(僕には見えます)、上ではO(N^2)、下ではO(N)です

 

上の分割は、下の分割を2回繰り返したものと同じになります。

あまり直感的でなく腹落ちしていないんですけど、できるだけシンプルな分割、遷移を考えるという感じでしょうか。

 

DPは苦手なので、二次元区間DPの1つとして頭に入れておこうと思います。