HCL (HashiCorp Configuration Language) は HashiCorp 社が開発している、シンプルな構文を持つ「プログラミング言語」です。
「プログラミング言語」なので、当然競技プログラミングに使用することもできます。
そしてTerraform は HCL によって記述された「プログラム」を実行するためのツールです。
というわけで、AtCoder の過去問精選 10 問を Terraform を使って解いてみます。
https://qiita.com/drken/items/fd4e5e3630d0f5859067
https://atcoder.jp/contests/abs
噂によると、 HCL を構造化設定言語 (structured configuration language) と呼び、 Terraform を使ってインフラを構築している人たちもいるらしいです。面白いですね。
今回紹介するコードは以下のリポジトリで管理しています。
テストコードや CI なども含まれています。
https://github.com/koki-develop/terraform-abs
var.input で文字列として受け取るvariable "input"{type= string}output.result で文字列として出力するoutput "result"{value="出力"}local-exec など ) は使用しないhttps://atcoder.jp/contests/abs/tasks/abc086_a
variable "input"{type= string}locals{# a, b を取得ab= split(" ", chomp(var.input))a= tonumber(local.ab[0])b= tonumber(local.ab[1])# a * b が偶数か奇数か判定result= local.a * local.b %2==0 ?"Even" :"Odd"}output "result"{value= local.result}input=<<EOT3 4EOT$ terraform apply -auto-approve# ...省略Outputs:result="Even"https://atcoder.jp/contests/abs/tasks/abc081_a
variable "input"{type= string}locals{# "1" の数をカウントcount= length([for a in split("", chomp(var.input)) : a if a=="1"])result= tostring(local.count)}output "result"{value= local.result}input=<<EOT101EOT$ terraform apply -auto-approve# ...省略Outputs:result="2"https://atcoder.jp/contests/abs/tasks/abc081_b
variable "input"{type= string}locals{# a1...an を数値に変換lines= split("\n", chomp(var.input))aa=[for a in split(" ", local.lines[1]) : tonumber(a)]# a1...an を 2 進数に変換bins=[for a in local.aa : format("%b", a)]# 2 進数の末尾の 0 の数 = 2 で割れる回数を数えるcounts=[for bin in local.bins : length(regex("0*$", bin))]# 最小値を取得result= tostring(min(local.counts...))}output "result"{value= local.result}input=<<EOT38 12 40EOT$ terraform apply -auto-approve# ...省略Outputs:result="2"https://atcoder.jp/contests/abs/tasks/abc087_b
variable "input"{type= string}locals{# a, b, c, x を取得lines= split("\n", chomp(var.input))a= tonumber(local.lines[0])b= tonumber(local.lines[1])c= tonumber(local.lines[2])x= tonumber(local.lines[3])# 各硬貨の組み合わせを計算し、条件に一致するものを取得combinations= flatten([for a in range(0, local.a +1) :[ for b in range(0, local.b +1) :[ for c in range(0, local.c +1) :true if a *500 + b *100 + c *50== local.x]]])# 条件に一致する組み合わせの数を取得result= tostring(length(local.combinations))}output "result"{value= local.result}input=<<EOT222100EOT$ terraform apply -auto-approve# ...省略Outputs:result="2"https://atcoder.jp/contests/abs/tasks/abc083_b
variable "input"{type= string}locals{# n, a, b を取得nab= split(" ", chomp(var.input))n= tonumber(local.nab[0])a= tonumber(local.nab[1])b= tonumber(local.nab[2])# 各整数の各桁の和を計算sums=[for i in range(1, local.n +1) : sum([for c in split("", tostring(i)) : tonumber(c)])]# 各桁の和が A から B の間にある整数のリストを作成valid_numbers=[for i in range(1, local.n +1) : i if local.a <= local.sums[i -1] && local.sums[i -1] <= local.b]# 総和を計算result= tostring(sum(local.valid_numbers))}output "result"{value= local.result}input=<<EOT20 2 5EOT$ terraform apply -auto-approve# ...省略Outputs:result="84"https://atcoder.jp/contests/abs/tasks/abc088_b
variable "input"{type= string}locals{# n, a1...an を取得lines= split("\n", chomp(var.input))n= tonumber(local.lines[0])aa=[for a in split(" ", local.lines[1]) : tonumber(a)]# カードを降順にソート、数値に変換sorted_cards=[# `sort` は文字列しかサポートしていないため、 0 埋めすることで数値順のソートを実現 for a_str in reverse(sort([ for a in local.aa : format("%03d", a)])) : tonumber(a_str)]# Alice と Bob の得点を計算alice= sum([for i in range(0, local.n,2) : local.sorted_cards[i]])bob= sum([for i in range(1, local.n,2) : local.sorted_cards[i]])# 得点差を計算result= tostring(local.alice - local.bob)}output "result"{value= local.result}input=<<EOT23 1EOT$ terraform apply -auto-approve# ...省略Outputs:result="2"https://atcoder.jp/contests/abs/tasks/abc085_b
variable "input"{type= string}locals{# n, d1...dn を取得lines= split("\n", chomp(var.input))n= tonumber(local.lines[0])dd=[for i in range(1, local.n +1) : tonumber(local.lines[i])]# 重複しない直径の数をカウントresult= tostring(length(toset(local.dd)))}output "result"{value= local.result}input=<<EOT410886EOT$ terraform apply -auto-approve# ...省略Outputs:result="3"https://atcoder.jp/contests/abs/tasks/abc085_c
variable "input"{type= string}locals{# n, y を取得lines= split("\n", chomp(var.input))ny= split(" ", local.lines[0])n= tonumber(local.ny[0])y= tonumber(local.ny[1])# 条件に一致する組み合わせを取得combinations= flatten([for x in range(0, local.n +1) :[ for y in range(0, local.n - x +1) :{count_10000= x,count_5000= y,count_1000= local.n - x - y,} if10000 * x +5000 * y +1000 * (local.n - x - y)== local.y]])# 単一の組み合わせを取得# 存在しない場合は -1 を設定combination= length(local.combinations) >0 ? local.combinations[0] :{count_10000= -1,count_5000= -1,count_1000= -1}# 結果文字列を形成result="${local.combination.count_10000}${local.combination.count_5000}${local.combination.count_1000}"}output "result"{value= local.result}input=<<EOT9 45000EOT$ terraform apply -auto-approve# ...省略Outputs:result="0 9 0"https://atcoder.jp/contests/abs/tasks/arc065_a
variable "input"{type= string}locals{# s を取得s= chomp(var.input)# 単語を削除result= replace( replace( replace( replace( local.s,"eraser","" ),"erase","" ) ,"dreamer","" ),"dream","" )=="" ?"YES" :"NO"}output "result"{value= local.result}input=<<EOTerasedreamEOT$ terraform apply -auto-approve# ...省略Outputs:result="YES"https://atcoder.jp/contests/abs/tasks/arc089_a
variable "input"{type= string}locals{# n を取得lines= split("\n", chomp(var.input))n= tonumber(local.lines[0])# 各時刻と座標をリストに格納t_x_y=[ for i in range(1, local.n +1) :{t= tonumber(split(" ", local.lines[i])[0]),x= tonumber(split(" ", local.lines[i])[1]),y= tonumber(split(" ", local.lines[i])[2])}]# 各ステップの情報をリストに格納steps=[ for i in range(0, local.n) :{current= local.t_x_y[i],prev= i==0 ?{t=0,x=0,y=0} : local.t_x_y[i -1]}]# 各ステップの移動可能性を判定movables=[ for step in local.steps : ( step.current.t - step.prev.t >= abs(step.current.x - step.prev.x) + abs(step.current.y - step.prev.y) && (step.current.t - step.prev.t - abs(step.current.x - step.prev.x) - abs(step.current.y - step.prev.y)) %2==0 )]# 全てのステップが移動可能であれば "Yes" そうでなければ "No"result= alltrue(local.movables) ?"Yes" :"No"}output "result"{value= local.result}input=<<EOT23 1 26 1 1EOT$ terraform apply -auto-approve# ...省略Outputs:result="Yes"AtCoder で正式にサポートされる日も近いですね。
バッジを受け取った著者にはZennから現金やAmazonギフトカードが還元されます。
