AtCoder Beginner Contest 232


A QQ solver

題解

把第一個和第三個字符轉換成數字乘起來就好

Code

點擊查看代碼
#include <cstdio>
int main()
{
    int a, b; scanf("%dx%d", &a, &b);
    printf("%d", a * b);
    return 0;
}

B Caesar Cipher

題解

把兩個字符串的每一位相減,判斷是否相等即可

需要特別注意的是,z 向右移動了 1是a,需要特殊判斷

Code

點擊查看代碼
#include <cstdio>
#include <cstring>
char a[100005], b[100005];
int main()
{
    scanf("%s", a);
    scanf("%s", b);
    if (std::strlen(a) != std::strlen(b)) {puts("No"); return 0;}
    int cha = -214;
    for (int i = 0; i < std::strlen(a); i++)
        if (int(b[i]) - int(a[i]) >= 0) cha = int(b[i]) - int(a[i]);
    if (cha == -214) cha = int(b[0]) - int(a[0]);
    for (int i = 0; i < std::strlen(a); i++) {
        if (int(b[i]) - int(a[i]) != cha && int('z' - a[i]) + int(b[i] - 'a') + 1 != cha) 
            {puts("No"); return 0;}
    }
    puts("Yes");
    return 0;
}

C Graph Isomorphism

題解

題意就是給你兩個圖,請你判斷他們是否同構

其實我們並不需要知道同構圖是什么,注意到 \(1\leq n\leq 8\) ,直接按照題意模擬,枚舉 \(P\) 的全排列再判斷條件能否成立

Code

點擊查看代碼
#include <cstdio>
#include <algorithm>
struct EDGE {
	int a, b;
	void swp() {
		if (a > b) std::swap(a, b);
	}
};
bool operator < (const EDGE & a, const EDGE & b) {
	return a.a == b.a ? a.b < b.b : a.a < b.a;
}
EDGE edge1[28], edge2[28], edge3[28];
int a[9];
int main() 
{
	int n, m; scanf("%d%d", &n, &m);
	for (int i = 0; i < m; i++) {
		scanf("%d%d", &edge1[i].a, &edge1[i].b);
		edge1[i].swp();
	}
	std::sort(edge1, edge1 + m);
	for (int i = 0; i < m; i++) 
        scanf("%d%d", &edge2[i].a, &edge2[i].b);
	for (int i = 1; i <= n; i++) a[i] = i;
	do {
		for (int i = 0; i < m; i++) {
			edge3[i].a = a[edge2[i].a];
                        edge3[i].b = a[edge2[i].b];
			edge3[i].swp();
		}
		std::sort(edge3, edge3 + m);
		bool flag = true;
		for (int i = 0; i < m; i++)
			if (edge1[i].a != edge3[i].a || edge1[i].b != edge3[i].b)
				{flag = false; break;}
		if (flag) {printf("Yes"); return 0;}
	} while (std::next_permutation(a + 1, a + n + 1));
	printf("No");
	return 0;
}

D Weak Takahashi

題解

一看數據范圍 \(1\leq H,W\leq 100\) ,直接DFS

每次判斷往左能不能走(注意一定記得不要走出界),如果不能就看看能不能往下走(也注意不要走出界),如果都不能直接返回就行

不需要回溯,因為到達的點數是函數的一個參數,返回時值自然就變成了遞歸之前的值

Code

點擊查看代碼
#include <cstdio>
#include <algorithm>
int n, m, ans = -1, num = 0;
char s[105][105];
bool vis[105][105];
void DFS(int x, int y, int num) {
    vis[x][y] = true, ans = std::max(ans, num);
    if (y < m && s[x][y + 1] == '.' && !vis[x][y + 1]) DFS(x, y + 1, num + 1);
    if (x < n && s[x + 1][y] == '.' && !vis[x + 1][y]) DFS(x + 1, y, num + 1);
    return;
}
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) scanf("%s", s[i] + 1);
    DFS(1, 1, 1);
    printf("%d", std::max(ans, num));
    return 0;
}

E Rook Path

題解

約定:我們令 \(N=H,M=W,N=H,M=W\),也就是說這個網格為 \(N\)\(M\) 列的。

再次考慮 DP,設 \(f_{x,y,k}\)表示執行 \(k\) 次操作,走到了 \((x,y)\) 這個位置的方案數。顯然邊界條件為 \(f_{x_1,y_1,0}=1\)

轉移:

\[f_{x,y,k}=\sum\limits_{1\le i\le N,i\not=x}f_{i,y,k-1}+\sum\limits_{1\le i\le M,i\not=y}f_{x,i,k-1} \]

答案:\(f_{x_2,y_2,k}\)

顯然,時間復雜度為 \(O\left(KN^3\right)=O(\text{過不了})\),考慮優化:減去無用狀態。


顯然,如果給定 \(k\),每個 \(f_{x,y,k}\)的取值只有四種可能,哪四種呢?

我們先設四個集合:

\(S_{0,0}=\{(x,y)|x=x_1,y=y_1\}\)

\(S_{0,1}=\{(x,y)|x=x_1,y\not=y_1\}\)

\(S_{1,0}=\{(x,y)|x\not=x_1,y=y_1\}\)

\(S_{1,1}=\{(x,y)|x\not=x_1,y\not=y_1\}\)

也就是說,

\(S_{0,0}\)是所有與 \((x_1,y_1)\)橫坐標相同,縱坐標相同的點的集合。
\(S_{0,1}\)是所有與 \((x_1,y_1)\)橫坐標相同,縱坐標不相同的點的集合。
\(S_{1,0}\)是所有與 \((x_1,y_1)\)橫坐標不相同,縱坐標相同的點的集合。
\(S_{1,1}\)是所有與\((x_1,y_1)\)橫坐標不相同,縱坐標不相同的點的集合。

然后我們發現,

\[\forall0\le a,b\le1,(x_1,y_1),(x_2,y_2)\in S_{a,b},0\le k\le K,f_{x_1,y_1,k}=f_{x_2,y_2,k} \]

在同一個集合中的點所對應的 \(f\) 值都相同(前提是 \(k\) 相同)。

所以我們設:

\[g_{a,b,k}=\sum\limits_{(x,y)\in{S_{a,b}}}f_{x,y,k},a,b\in\{0,1\} \]

\(g_{a,b,k}\)表示所有在 \(S_{a,b}\)中的點的 \(f\) 值的和(給定 \(k\))。

邊界條件:\(g_{0,0,0}=1\)


易得轉移方程

\[g_{0,0,k}=g_{0,1,k-1}+g_{1,0,k-1} \]

\[g_{0,1,k}=(M-1)f_{0,0,k-1}+(M-2)f_{0,1,k-1}+f_{1,1,k-1} \]

\[g_{1,0,k}=(N-1)f_{0,0,k-1}+(N-2)f_{1,0,k-1}+f_{1,1,k-1} \]

\[g_{1,1,k}=(N-1)f_{0,1,k-1}+(M-1)f_{1,0,k-1}+[(N-2)+(M-2)]f_{1,1,i-1} \]

如何推導?考慮每個狀態可以怎么轉移過來。

如果 \(x_1=x_2,y_1=y_2\)\(\operatorname{Answer}=g_{0,0,K}\)

如果 \(x_1=x_2,y_1\not=y_2\)\(\operatorname{Answer}=\dfrac{g_{0,1,K}}{M-1}\)

如果 \(x_1\not=x_2,y_1=y_2\)\(\operatorname{Answer}=\dfrac{g_{0,1,K}}{N-1}\)

如果 \(x_1\not=x_2,y_1\not=y_2\)\(\operatorname{Answer}=\dfrac{g_{0,1,K}}{(N-1)(M-1)}\)

除法使用求逆元完成。

Code

點擊查看代碼
#include <cstdio>
typedef long long ll;
const ll mod = 998244353;
ll f[2][2][1000005];
ll inv(ll x) {
	return x == 1 ? 1 : (mod - mod / x) * inv(mod % x) % mod;
}
int main() 
{
	int n, m, k; scanf("%d%d%d", &n, &m, &k);
	int x1, y1, x2, y2; scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
	f[0][0][0] = 1;
	for (int i = 1; i <= k; i++) {
		f[0][0][i] = (f[0][1][i - 1] + f[1][0][i - 1]) % mod;
		f[0][1][i] = ((m - 1) * f[0][0][i - 1] % mod + (m - 2) * f[0][1][i - 1] % mod + f[1][1][i - 1]) % mod;
		f[1][0][i] = ((n - 1) * f[0][0][i - 1] % mod + (n - 2) * f[1][0][i - 1] % mod + f[1][1][i - 1]) % mod;
		f[1][1][i] = ((n - 1) * f[0][1][i - 1] % mod + (m - 1) * f[1][0][i - 1] % mod + (n + m - 4) * f[1][1][i - 1] % mod) % mod;
	}
	ll ans;
	if (x1 == x2 && y1 == y2) ans = f[0][0][k];
	else if (x1 == x2 && y1 != y2) ans = f[0][1][k] * inv(m - 1) % mod;
	else if (x1 != x2 && y1 == y2) ans = f[1][0][k] * inv(n - 1) % mod;
	else ans = f[1][1][k] * inv((n - 1) * (m - 1) % mod) % mod;
	printf("%lld", ans);
	return 0;
}
// 語言選C++(Clang 10.0.0)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM