AtCoder Regular Contest 013
なんだかやる気がでないので競技に逃げ続けている。
A - 梱包できるかな?
向きを固定すれば、各方向に入る数の積で入る総数がでる。これを全ての荷物の向きに対して試せばよい。
最初問題文を少し勘違いして、Aなのに難しすぎるでしょどうやるんだ、ってなってた。
彼はとても几帳面な性格なので、荷物を全て同じ向きで梱包します。
ただし、荷物を横に90度倒すことはできます。
というのを、x,y軸の周りでは回転できないがz軸の周りでは回転できる、と誤読していた。
#include <iostream>
#include <algorithm>
#define repeat_from(i,m,n) for (int i = (m); (i) < (n); ++(i))
#define repeat(i,n) repeat_from(i,0,n)
using namespace std;
int main() {
int a[3], b[3];
repeat (i,3) cin >> a[i];
repeat (i,3) cin >> b[i];
sort(b, b + 3);
int result = 0;
do {
int acc = 1;
repeat (i,3) acc *= a[i] / b[i];
result = max(result, acc);
} while (next_permutation(b, b + 3));
cout << result << endl;
return 0;
}
始め難易度勘違いしてたのと、next_permutation
の存在からc++。pythonにもitertools.permutations
ってのがあるっぽいのでpythonで十分だった。
import Control.Applicative
import Data.List
main = do
xs <- map read . words <$> getLine
ys <- map read . words <$> getLine
print . maximum . map (product . zipWith div xs) $ permutations ys
Bがhaskellで1行だったので、ついでにAもやってみた。
B - 引越しできるかな?
荷物それぞれについて各方向の大きさをソートして、1,2,3番目の方向それぞれについて最大値を取ればよい。
これも問題文勘違いして、少しの間絶望感につつまれてた。すぐに1つの箱に1つの荷物だと気付いて安堵した。
#!/usr/bin/env python3
c = int(input())
xs = 0, 0, 0
for i in range(c):
ys = map(int,input().split())
xs = map(max, xs, sorted(ys))
xs = list(xs)
print(xs[0] * xs[1] * xs[2])
これtranspose
で一撃では、と思ったのでhaskellを書いた。でもpythonでもzip(*xss)
と書けば転置できるようだ。
import Data.List
main = getContents >>= print . product . map maximum . transpose . map (sort . map read . words) . tail . lines
読めない。golfの点ではrubyに負けてた。
C - 笑いをとれるかな?
今の私にとって丁度よい難易度で考えてて楽しかった。
ただし1-indexedと0-indexedを取り違えて1WA。問題文中の図が3つ中2つ404していたのも原因の1つなので許されるべき。
問題
ハバネロがいくつか埋め込まれた豆腐がいくつか与えられる。豆腐を1つ選び座標軸に並行に切り片方を食べる、これを交互に繰り返す。先に食べた方の負け。必勝手番を求める。
解法
まず、豆腐が複数個存在することについて。これは明らかにゲームの和であり、1つの豆腐上のゲームのgrundy数を求める問題へと帰着される。
次に、豆腐のgrundy数について。豆腐の1辺の大きさは$10^9$と大きく、愚直に計算することはできない。 ここで、厚みが1で縦横共に$10^9$で左上にのみハバネロを持つ豆腐を考える。ハバネロを含む1x1x1の区画のみの状態から逆向きに考えていくと、その過程は縦軸と横軸それぞれの方向のゲームの和そのものであることに気付ける。よってこれを一般化し、ハバネロを含む長方形の区画の6つの面に鉛直な方向のゲーム6つの和で、1つの豆腐上のゲームが表せる。
解答
A,Bがhaskellゲーだったのでhaskell。
最初に書いたものは入力が大きいケースでTLEした。
!
やseq
付けたら縮んだけど全然足りなくて、haskellは競技プログラミングに向いていないのか、とか言ってた。
ByteString
を使うようにしたら100倍ほど高速化して通った。単に私の知識不足だった。なんだかちょっと恥ずかしい。
import Control.Arrow
import Control.Monad
import Data.Bits
import Data.List
import Data.Maybe
import qualified Data.ByteString.Char8 as B
readInt = fst . fromJust . B.readInt
getInts = map readInt . B.words <$> B.getLine
main :: IO ()
main = do
n <- readInt <$> B.getLine
gs <- replicateM n $ do
[x, y, z] <- getInts
m <- readInt <$> B.getLine
habaneros <- replicateM m getInts
let [(xl,xr),(yl,yr),(zl,zr)] = map (minimum &&& maximum) $ transpose habaneros
return $ foldl1 xor [xl, x - xr - 1, yl, y - yr - 1, zl, z - zr - 1]
putStrLn . (\ g -> if g == 0 then "LOSE" else "WIN") $ foldl1 xor gs
haskellがなかなか通らないので一旦諦めてc++も書いた。
#include <iostream>
#include <vector>
#include <algorithm>
#define repeat_from(i,m,n) for (int i = (m); (i) < (n); ++(i))
#define repeat(i,n) repeat_from(i,0,n)
using namespace std;
int main() {
int n; cin >> n;
int g = 0;
repeat (i,n) {
int x, y, z; cin >> x >> y >> z;
int m; cin >> m;
vector<int> xs(m), ys(m), zs(m);
repeat (j,m) cin >> xs[j] >> ys[j] >> zs[j];
int xl = *min_element(xs.begin(), xs.end()); int xr = *max_element(xs.begin(), xs.end());
int yl = *min_element(ys.begin(), ys.end()); int yr = *max_element(ys.begin(), ys.end());
int zl = *min_element(zs.begin(), zs.end()); int zr = *max_element(zs.begin(), zs.end());
g ^= xl ^ (x - xr - 1);
g ^= yl ^ (y - yr - 1);
g ^= zl ^ (z - zr - 1);
}
cout << (g == 0 ? "LOSE" : "WIN") << endl;
return 0;
}
なぜ全問それぞれ2言語で書いてしまったのか。