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_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)\)橫坐標不相同,縱坐標不相同的點的集合。
然后我們發現,
在同一個集合中的點所對應的 \(f\) 值都相同(前提是 \(k\) 相同)。
所以我們設:
\(g_{a,b,k}\)表示所有在 \(S_{a,b}\)中的點的 \(f\) 值的和(給定 \(k\))。
邊界條件:\(g_{0,0,0}=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)