AtCoder Beginner Contest 212に参加したので、その時に考えていたこととか、解法のメモなんかを。
「C# .NET Core 3.1.201」での参加。
A,BはAC。Cで時間切れ。D以降は未回答。
A問題 - Alloy
与えられたAとBを、示されている条件通りに分岐処理すればOK。
probA.cs
using System;
using System.Collections.Generic;
using System.Linq;
class Program {
static void Main() {
var sw = new System.IO.StreamWriter(Console.OpenStandardOutput()) {
AutoFlush = false
};
Console.SetOut(sw);
var input = Console.ReadLine().Split(' ').Select(x => int.Parse(x)).ToList();
var a = input[0];
var b = input[1];
var ans = "";
if (0 < a && b == 0) {
ans = "Gold";
} else if (a == 0 && 0 < b) {
ans = "Silver";
} else if (0 < a && 0 < b) {
ans = "Alloy";
}
Console.WriteLine(ans);
Console.Out.Flush();
}
}
B問題 - Weak Password
与えられる4桁の暗証番号について、次のいずれかの条件を満たすと「弱い」暗証番号となる問題。
いずれか、なのでどちらか一方でも満たせば答えは"Weak"となる。
二つの条件のうち、少し考えたのが二つ目のほう。
次の数字が+1になっていれば「弱い」暗証番号であるが、肝心なのは
$ i $ が $1 \leq i\leq 3$を満たす任意の整数であるということ。
一回目の提出の時、この文言を完全に読み飛ばしており、
どこか一つでも$ X_{i + 1} $が$ X_1 $の次の数字になっていればよい、という条件で提出してしまい惨敗。
落ち着いてサンプル問題を見直して、条件の読み取り間違いに気付きかろうじてAC。
probB.cs
using System;
using System.Collections.Generic;
using System.Linq;
class Program {
static void Main() {
var sw = new System.IO.StreamWriter(Console.OpenStandardOutput()) {
AutoFlush = false
};
Console.SetOut(sw);
var input = Console.ReadLine();
var ans = "Strong";
if (input[0] == input[1] && input[0] == input[2] && input[0] == input[3]) {
ans = "Weak";
}
var count = 0;
for (var i = 0; i < 3; i++) {
var number = int.Parse(input[i].ToString());
var nextNumber = int.Parse(input[i + 1].ToString());
if (number <= 8 && number + 1 == nextNumber) {
count++;
} else if (number == 9 && nextNumber == 0) {
count++;
}
if (count == 3) {
ans = "Weak";
}
}
Console.WriteLine(ans);
Console.Out.Flush();
}
}
C問題 - Min Difference
与えられる二つの数列から一つずつ要素を選択して、差が最小になる組み合わせを探す問題。
制約から単純に組み合わせ総当たりでは間に合わないため、何らかの工夫が必要。
おそらくソートしてどうにかこうにかするんだろうなぁ…というところで時間切れ。
解法のポイントは、$A_i$と$B_j$の大小関係。
二つの数列の並びが昇順となっている場合、
$A_i \leq B_j $であるなら、$j \leq j'$ について常に$|A_i - B_j| \leq |A_i - B_{j'}|$が成り立つ。
そのため、$j'$以降を調べる必要がなくなる。
同様の考え方で、$A_i > B_j$のとき、$j' < j$について、常に$|A_i - B_j| < |A_{i+1} - B_j'|$が成り立つ。
つまり、順に走査していくなかで、$A_i$より$B_j$が大きい時点で、$B_j$よりさらに大きい$B_{j+1}$以降については差がさらに開く一方であることが明らかであり、
$B_{j-1}$以下についても$A_{i+1}$との差は$A_i$と$B_j$の差より大きくなるということ。
probC.cs
using System;
using System.Collections.Generic;
using System.Linq;
class Program {
static void Main() {
var sw = new System.IO.StreamWriter(Console.OpenStandardOutput()) {
AutoFlush = false
};
Console.SetOut(sw);
var input = Console.ReadLine().Split(' ').Select(x => int.Parse(x)).ToList();
var n = input[0];
var m = input[1];
var a = Console.ReadLine().Split(' ').Select(x => int.Parse(x)).ToList();
var b = Console.ReadLine().Split(' ').Select(x => int.Parse(x)).ToList();
var ans = 1010000000;
a.Sort();
b.Sort();
int x = 0, y = 0;
while ((x < n) && (y < m)) {
ans = Math.Min(ans, Math.Abs(a[x] - b[y]));
if (a[x] > b[y]) {
y++;
} else {
x++;
}
}
Console.WriteLine(ans);
Console.Out.Flush();
}
}
感想
まずは問題の条件をしっかりを読んで理解すること。
今回のC問題のようなときは、具体例を紙に書いてシミュレーションしてみること。
↧