はじめに
AtCoder Beginner Contest 242の復習記事です。
記事におけるScanner
クラスは、自作の入力クラスです。
コンテスト
https://atcoder.jp/contests/abc242
問題A
それぞれどの条件に当てはまるかで確率を求めます。
X <= A
ならば確率は1
A+1 <= X <= B
ならば確率はC/(B-A)
B < X
ならば確率は0
public static void Solve()
{
var (A, B, C, X) = Scanner.Scan<int, int, int, int>();
var answer = 0d;
if (X <= A) answer = 1d;
if (A + 1 <= X && X <= B) answer = (double)C / (B - A);
Console.WriteLine(answer);
}
問題B
辞書順最小となる文字列は、文字列S
を構成する文字のうち、小さいものを左から順に並べたものになります。
そのため、文字列S
をソートした文字列が答えとなります。
public static void Solve()
{
var S = Scanner.Scan<string>().ToCharArray();
Array.Sort(S);
var answer = new string(S);
Console.WriteLine(answer);
}
問題C
動的計画法で答えとなる個数を数え上げます。
初期値として、1桁目は1
から9
である個数をそれぞれ1
とします。
i
桁目の数値がj
のとき、i+1
桁目には、j-1
、j
、j+1
に遷移することができます。N
桁目まで確定したときの、1
から9
までの個数の和が答えとなります。
数え上げのときに0
と10
に遷移できるスペースを確保しておくと、j=0
の時のj-1
の遷移とj=9
のときのj+1
でif
文が不要になります。
mint
は、Mod
として指定した数値で余りをとった整数をもつ構造体です。
public static void Solve()
{
var N = Scanner.Scan<int>();
var dp = new mint[N + 1, 11];
for (var i = 1; i < 10; i++)
{
dp[1, i] = 1;
}
for (var i = 1; i < N; i++)
{
for (var j = 1; j < 10; j++)
{
dp[i + 1, j - 1] += dp[i, j];
dp[i + 1, j] += dp[i, j];
dp[i + 1, j + 1] += dp[i, j];
}
}
mint answer = 0;
for (var i = 1; i < 10; i++)
{
answer += dp[N, i];
}
Console.WriteLine(answer);
}
問題D
コンテスト中の考察です。
t=0
ならば、S[k]
k=0
ならば、S[0]+t
t>60
ならば、S[0]
から派生したところになりそう。t>0
かつk>0
のときの周期は?
解説では、F(t,k)
となる文字は、再帰的に求めることができるそうです。
t=0
ならば、F(t,k)=S[k]
k=0
ならば、F(t,k)=S[0]+t
- それ以外ならば、
F(t,k)
=F(t-1,k/2)+k%2+1
F
はO(logk)
で求めることができます。
public static void Solve()
{
var S = Scanner.Scan<string>();
var N = S.Length;
var Q = Scanner.Scan<int>();
while (Q-- > 0)
{
var (t, k) = Scanner.Scan<long, long>();
var answer = F(t, k - 1);
Console.WriteLine(answer);
}
char G(char c, long d)
{
return (char)((c - 'A' + d) % 3 + 'A');
}
char F(long t, long k)
{
if (t == 0) return S[(int)k];
if (k == 0) return G(S[0], t);
return G(F(t - 1, k / 2), k % 2 + 1);
}
}
問題E
辞書順で文字列S
以下の文字列を考えます。
回文のため、文字列S
の前半分の文字列S'
において、S'
未満の個数を数え上げを行います。
この数え上げは、S'
の文字をそれぞれ0-25
の26進数としたときの個数として数え上げることができます。
また、文字列S
の前半分を回文にした文字列をT
としたとき、S
以下ならば、答えを1増やします。
例えば、S=ABCDE
ならば、S'=ABC
なので、前半の数え上げは26^2*0 + 26^1*1 + 26^0*2 = 28
となり、T=ABCBA<=S
なので答えは29
になります。
public static void Solve()
{
var Q = Scanner.Scan<int>();
while (Q-- > 0)
{
var N = Scanner.Scan<int>();
var S = Scanner.Scan<string>();
var T = S.ToCharArray();
for (var i = 0; i < (N + 1) / 2; i++)
{
T[N - 1 - i] = T[i];
}
mint answer = 0;
for (var i = 0; i < (N + 1) / 2; i++)
{
answer *= 26;
answer += T[i] - 'A';
}
if (new string(T).CompareTo(S) <= 0) answer++;
Console.WriteLine(answer);
}
}