はじめに
AtCoder Beginner Contest 266の復習記事です。
記事におけるScanner
クラスは、自作の入力クラスです。
コンテスト
https://atcoder.jp/contests/abc266
問題A
文字列S
の長さが奇数なので、S
のインデックスFloor(Sの長さ/2)
の文字が答えとなります。
public static void Solve()
{
var S = Scanner.Scan<string>();
var N = S.Length;
Console.WriteLine(S[N / 2]);
}
問題B
N-x
が998244353
の倍数であるということは、N
を998244353
で割ったときの余りがx
になることがわかります。
また、言語によって負の数に対する余りの計算は異なり、余りが負の値になる場合があります。
a
をb(!=0)
で割ったときの余りがc
のとき、a+b
やa-b
をb
で割ったときの余りもc
になることから、x
が負の値のときは998244353
を足すことで、0<=x<=998244353
にすることができます。
public static void Solve()
{
var N = Scanner.Scan<long>();
const long M = 998244353;
var x = N % M;
if (x < 0) x += M;
Console.WriteLine(x);
}
問題C
全ての角が180度未満であるかを外積を用いて判定します。
角abc
の外積はcross=(c.X-b.X)*(a.Y-b.Y)-(a.X-b.X)*(c.Y-b.Y)
で計算でき、abc
が反時計回りならcross>=0
の場合角abc
の角は180
度未満になります。
public static void Solve()
{
var N = 4;
var P = new Point[N];
for (var i = 0; i < N; i++)
{
var (x, y) = Scanner.Scan<int, int>();
P[i] = new Point(x, y);
}
long Cross(Point a, Point b, Point c)
{
var (dx1, dy1) = (c.X - b.X, c.Y - b.Y);
var (dx2, dy2) = (a.X - b.X, a.Y - b.Y);
return dx1 * dy2 - dx2 * dy1;
}
var answer = true;
for (var i = 0; i < N; i++)
{
var a = P[i];
var b = P[(i + 1) % N];
var c = P[(i + 2) % N];
answer &= Cross(a, b, c) >= 0;
}
Console.WriteLine(answer ? "Yes" : "No");
}
public readonly struct Point
{
public readonly long X;
public readonly long Y;
public Point(long x, long y) => (X, Y) = (x, y);
}
問題D
dp[t][x]:=時刻tの座標xにおける既に捕まえた大きさの最大値
とした動的計画法を解きます。
これは、時刻t
の座標x
における大きさをA[t][x]
としたとき、dp[t][x] = Max(dp[t-1][x-1], dp[t-1][x], dp[t-1][x+1]) + A[t][x]
の遷移で求めることができます。
public static void Solve()
{
var N = Scanner.Scan<int>();
var A = new long[(int)1e5 + 1, 5];
var T = 0;
for (var i = 0; i < N; i++)
{
var (t, x, a) = Scanner.Scan<int, int, long>();
A[t, x] = a;
T = t;
}
const long inf = (long)1e18;
var dp = new long[T + 1, 5];
for (var i = 0; i <= T; i++)
{
for (var j = 0; j < 5; j++)
{
dp[i, j] = -inf;
}
}
dp[0, 0] = 0;
for (var t = 1; t <= T; t++)
{
for (var x = 0; x < 5; x++)
{
for (var p = x - 1; p <= x + 1; p++)
{
if (0 <= p && p < 5) dp[t, x] = Math.Max(dp[t, x], dp[t - 1, p] + A[t, x]);
}
}
}
var answer = 0L;
for (var i = 0; i < 5; i++)
{
answer = Math.Max(answer, dp[T, i]);
}
Console.WriteLine(answer);
}
問題E
n
回目の期待値は、n-1
回目の期待値と出目を比較して大きいほうを選んだときの1-6
の出目の総和になります。
public static void Solve()
{
var N = Scanner.Scan<int>();
var answer = 0.0;
for (var i = 0; i < N; i++)
{
var exp = 0.0;
for (var x = 1; x <= 6; x++)
{
exp += Math.Max(x, answer) / 6.0;
}
answer = Math.Max(answer, exp);
}
Console.WriteLine(answer);
}