AtCoder Beginner Contest 011

A

Problem

Given the current month \(m\) , what month is the \(next\) ?

Solutions

The base of month is \(12\) .

m = m - 1
m = (m + 1) % 12
m = m + 1
print(m)

\(((m - 1) + 1) \% 12 + 1 = m \% 12 + 1\)

B

Problem

Given a string \(S\) , modify it to meet the following conditions :

  • The first character is capitalized.
  • The second to last character is lowecase.

Solutions

    std::string s; std::cin >> s;
    for (int i = 0; i < (int)s.size(); i++) {
        if ('a' <= s[0] && s[0] <= 'z') s[0] = char(s[0] - 'a' + 'A');
        else if (i > 0 && 'A' <= s[i] && s[i] <= 'Z') s[i] = char(s[i] - 'A' + 'a');
    }
    std::cout << s << "\n";

C

Problem

Given a number \(N\) and threr number \(A, B, C\) . Execute the following operations :

  • Choose on of the numbers \(1\) , \(2\) of \(3\) and subtract it from \(N\) .
  • \(N\) has never been equal to any one of \(A\) , \(B\) or \(C\) .
  • Loop operation, but with a maximum of \(100\) operations.
    Answer whether \(N\) can become \(0\) ?

Solutions

We just need to use dynamic programming.
dp[considering \(x\)], the minimum number of operations.

\[dp_{i} = MIN_{j = 1}^{3} dp_{i + j} + 1 \quad s.t. \quad i, i + j \not \in \{A, B, C\} \wedge i + j \leq N \]

Be careful that the initial value is \(dp[N] = [N \in \{A, B, C\}] \ ? \ +\infty \ : \ 0\) .
Finally we check if \(dp[0] \leq 100\) .

There are \(N\) sates, and the time for transtion is \(T(3)\) , the time for checking whether transition is possible is \(\log 3\) .
So the time complexity of DP is \(T(N \times 3 \times \log 3) = O(N)\) .

view
    int N; std::cin >> N;
    
    int v[3] = {0}; for (int i = 0; i < 3; i++) std::cin >> v[i];
    std::sort(v, v + 3);
    
    auto forbid = [&] (int x) -> bool {
        int p = std::lower_bound(v, v + 3, x) - v;
        if (p < 3 && x == v[p]) return true;
        else return false;
    };

    std::vector<int> dp(N + 1, 1 << 30);
    dp[N] = forbid(N) ? 1 << 30 : 0;
    for (int i = N; i >= 0; --i) {
        for (int j = 1; j <= 3; j++) {
            if (forbid(i) || forbid(i + j)) continue;
            if (i + j <= N && dp[i + j] < 1 << 30) {
                dp[i] = std::min(dp[i], dp[i + j] + 1);
            }
        }
    }
    std::cout << (dp[0] <= 100 ? "YES" : "NO") << "\n";

D

Problem

In the Cartesian coordinate system, there is a starting point \((0, 0)\) and an ending point \((X, Y)\) .

If you are currently at point \((x, y)\) . You can move by juming, and choose one of the following jumping methods with equal probability each time.

  • jumping to \((x + D, y)\) .
  • jumping to \((x - D, y)\) .
  • jumping to \((x, y + D)\) .
  • jumping to \((x, y - D)\) .

You should jump exactly \(N\) times. Ask about the possibility of reaching the ending point.

\(-10^{9} \leq X, Y, \leq 10^{9}, N \leq 1000\)

Solutions

First of all, we would better divide \(X\) and \(Y\) by \(D\) . If \(D \mid X\) or \(D \mid Y\) , the possibility of reaching the ending point is \(0\) . And more, we can divide \(X\) by \(D\) and divide \(Y\) by \(D\) .

Second, \(0 \leq |X|, |Y| \leq 10^{9}\) is crazy? If \(|X| + |Y| > N\) there are no solution.

Three, the probability of going left and right is equal, and the probability of going up and down is also equal. So we can make \((X, Y)\) equal to \((|X|, |Y|)\) to aviod negative number as well as somplify the handing of problems.

Using DP to solve it is obvious.

dfs(\(\textbf{remaining number of moves} \ count\), \(nowX\), \(nowY\))

We observe the numbers of states, only \(N \times N \times N = O(N^{3})\) .

So we can use memorize search or Dynamic Programming .

The space should contain \([-N, N]\) so that we allocate the space of \([0, 2 N + 1]\) and define an array offset \(B = N\) .

Dynamic Programming
	int N, D, X, Y; std::cin >> N >> D >> X >> Y;
	if (X < 0) X *= -1;
	if (Y < 0) Y *= -1;
	if (X % D != 0 || Y % D != 0) {
		std::cout << std::fixed << std::setprecision(12) << 0.L << "\n";
		return;
	}
	X /= D; Y /= D;
	if (X + Y > N) {
		std::cout << std::fixed << std::setprecision(12) << 0.L << "\n";
		return;
	}
	assert(N <= 200);
	int B = N;
	std::vector<std::vector<std::vector<db> > > f(2 * N + 1,
		std::vector<std::vector<db> > (2 * N + 1,
			std::vector<db>(2 * N + 1, -1.L)));
	std::function<db(int, int , int)> dfs = [&] (int rem, int x, int y) -> db {
		assert(0 <= rem && rem <= N); assert(0 <= B + x && B + x <= 2 * N); assert(0 <= B + y && B + y <= 2 * N);
		db &res = f[rem][B + x][B + y];
		if (sgn(res) != -1) return res;
		else res = 0.L;
		if (rem == 0) {
			if (x == X && y == Y) return res = 1.L;
			else return res = 0.L;
		}
		int dir[][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
		for (int i = 0; i < 4; i++) res += 1.L / 4 * dfs(rem - 1, x + dir[i][0], y + dir[i][1]);
		return res;
	};
	dfs(N, 0, 0);
	std::cout << std::fixed << std::setprecision(12) << f[N][B + 0][B + 0] << "\n";

But that's still not enough.

Be aware of the question only needs to be answered in step \(N\) , and the transition probability is symmetric.

The size of sample space is obviously \(4^{N}\) , then wa calculate the size of random event \(\mathbb{A}\) that \(N\)-th step can reach the finish point \(X, Y\) .

If we take \(K \ (0 \leq K \leq N)\) steps in the \(1\)-st dimension, \(A\) steps forward, \(B\) steps backward, we have :

\[\begin{cases} A + B = X \\ A - B = K \\ \end{cases} \Rightarrow \begin{cases} A = \frac{K + X}{2} \\ B = \frac{K - X}{2} \\ \end{cases} \]

Similarly, we take \(N - K \ (0 \leq K \leq N)\) steps in the \(2\)-st dimension, \(C\) steps forward, \(D\) steps backward, we have :

\[\begin{cases} C + D = N - K \\ C - D = Y \\ \end{cases} \Rightarrow \begin{cases} C = \frac{N - K + Y}{2} \\ D = \frac{N - K - Y}{2} \\ \end{cases} \]

At the end we get :

\[|\mathbb{A}| = \sum_{K = 0}^{N} \binom{N}{K} \binom{K}{(K + X)/2} \binom{N - K}{(N - K + Y)/2} \quad s.t. \ A,B,C,D \in \mathbb{Z} \wedge 0 \leq min\{A,B,C,D\} \]

The last qustion. If we don't used inverer element, how do we store combination numbers?

We can maintain \(\frac{\binom{n}{m}}{2^{n}}\) by \(\binom{n}{m} = \binom{n - 1}{m - 1} + \binom{n - 1}{m}\) , such that :

\[\begin{aligned} \begin{cases} f[0][0] &= \binom{0}{0} \\ f[i][0] &= f[i][i] = \frac{1}{2} \binom{i - 1}{0} \quad s.t. 1 \leq i \leq N \\ f[n][k] &= (f[n - 1][k] + f[n - 1][k - 1]) / 2 \quad s.t. 0 < k < i \\ \end{cases} \end{aligned} \]

So

\[\begin{aligned} \mathcal{P}(\mathbb{A}) &= \frac{\sum_{K = 0}^{N} \binom{N}{K} \binom{K}{(K + X)/2} \binom{N - K}{(N - K + Y)/2}}{4^{N}} \\ &= \sum_{K = 0}^{N} f[N][K] \times f[K][(K + X) / 2] \times f[N - K][(N - K + Y) / 2] \times \frac{2^{N} \times 2^{K} \times 2^{N - K}}{4^{N}} \\ &= \sum_{K = 0}^{N} f[N][K] \times f[K][(K + X) / 2] \times f[N - K][(N - K + Y) / 2] \\ \end{aligned} \]

The bottleneck of time complexity is the preprocessing of combination numbers which \(O(N^{2})\) .
The time complexity of the calculate of the probability is \(O(N)\) .

Math Solution
	int N, D, X, Y; std::cin >> N >> D >> X >> Y;
	if (X < 0) X *= -1;
	if (Y < 0) Y *= -1;
	if (X % D != 0 || Y % D != 0) {
		std::cout << std::fixed << std::setprecision(12) << 0.L << "\n";
		return;
	}
	X /= D; Y /= D;
    if (X + Y > N) {
        std::cout << std::fixed << std::setprecision(12) << 0.L << "\n";
		return;
    }
	std::vector<std::vector<db> > f(N + 1, std::vector<db>(N + 1, 0));
	f[0][0] = 1;
	for (int i = 1, p = 2; i <= N; i++, p *= 2) {
		f[i][0] = f[i][i] = f[i - 1][0] / 2;
		for (int j = 1; j < i; j++) f[i][j] = (f[i - 1][j - 1] + f[i - 1][j]) / 2;
	}
	auto check = [&] (int n) -> bool {
		return n >= 0 && ~n & 1;
	};
    db ans = 0;
	for (int K = 0; K <= N; K++) {
		if (check(K + X) && check(K - X) && check(N - K + Y) && check(N - K - Y)) {
			ans += f[N][K] * f[K][(K + X) / 2] * f[N - K][(N - K + Y) / 2];
		}
	}
	std::cout << std::fixed << std::setprecision(12) << ans << "\n";
posted @ 2024-08-16 23:28  03Goose  阅读(44)  评论(0)    收藏  举报
📑 文章目录