[ARC 188A] ABC Symmetry
solution by XiangXunYi
思路推导
step 1
首先题目中操作二同时删掉 A
,B
,C
的条件相当于同时将三者数量减一,操作一删掉两个相同字符等同于将某一字符的数量减二,那么我们可以发现只使用操作一不会改变奇偶,操作二则是同时反转奇偶,所以一个字符串是个好字符串的必要条件是其中三个字母数量的奇偶性相同,同时容易构造出一组解使其变为空字符串,故也是必要条件。
构造解:执行操作一直到不能执行为止,最后视情况执行操作二。
step2
由于题目的抽象数据范围较小且对于问号的抉择相互影响较大,联想到 dp。首先会想到把
step 3
设一段区间 A
的数量对 B
的数量对 C
的数量对
因为好字段必须要三个字符数量奇偶性相同,抽象的理解为
在这种 dp 状态的设计下,我们可以发现,四种情况不重不漏的涵盖了所有区间,当一个区间满足右端点和左端点减一是同一种情况就是一个好子段,最后好子段的个数就是
step 4
定义有了,该题的转移并不难想,只要根据上一个位置的状态加上当前位置的字符即可转移(给个建议:用刷表)。
solution
定义
对于当前字符为 A
时,情况
对于当前字符为 B
时,情况
对于当前字符为 C
时,情况
int pos = i + j + k + l;
int tmp[4] = { i, j, k, l };
int x = lst ^ 3, y = lst ^ 1, z = lst ^ 2;
if ((s[pos] == '?' || s[pos] == 'A') && tmp[x] + 1 <= n) {
tmp[x]++;
trans(dp[tmp[0]][tmp[1]][tmp[2]][tmp[3]][x] , dp[i][j][k][l][lst]);
tmp[x]--;
}
if ((s[pos] == '?' || s[pos] == 'B') && tmp[y] + 1 <= n) {
tmp[y]++;
trans(dp[tmp[0]][tmp[1]][tmp[2]][tmp[3]][y] ,dp[i][j][k][l][lst]);
tmp[y]--;
}
if ((s[pos] == '?' || s[pos] == 'C') && tmp[z] + 1 <= n) {
tmp[z]++;
trans(dp[tmp[0]][tmp[1]][tmp[2]][tmp[3]][z] , dp[i][j][k][l][lst]);
tmp[z]--;
}
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 55;
const int mod = 998244353;
int n, least, dp[N][N][N][N][4];
char s[55];
inline void trans(int& x, int y) { x = (x + y) % mod; }
int main() {
scanf("%d%d%s", &n, &least, s);
dp[0][0][0][0][0] = 1;
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
for (int k = 0; k < n; ++k)
for (int l = 0; l < n; ++l)
if (i + j + k + l < n)
for (int lst = 0; lst < 4; ++lst) {
int pos = i + j + k + l;
int tmp[4] = { i, j, k, l };
int x = lst ^ 3, y = lst ^ 1, z = lst ^ 2;
if ((s[pos] == '?' || s[pos] == 'A') && tmp[x] + 1 <= n) {
tmp[x]++;
trans(dp[tmp[0]][tmp[1]][tmp[2]][tmp[3]][x] , dp[i][j][k][l][lst]);
tmp[x]--;
}
if ((s[pos] == '?' || s[pos] == 'B') && tmp[y] + 1 <= n) {
tmp[y]++;
trans(dp[tmp[0]][tmp[1]][tmp[2]][tmp[3]][y] ,dp[i][j][k][l][lst]);
tmp[y]--;
}
if ((s[pos] == '?' || s[pos] == 'C') && tmp[z] + 1 <= n) {
tmp[z]++;
trans(dp[tmp[0]][tmp[1]][tmp[2]][tmp[3]][z] , dp[i][j][k][l][lst]);
tmp[z]--;
}
}
int ans = 0;
for (int i = 0; i <= n; ++i)
for (int j = 0; j <= n; ++j)
for (int k = 0; k <= n; ++k)
for (int l = 0; l <= n; ++l)
for (int lst = 0; lst < 4; ++lst)
if (i + j + k + l == n && i * (i + 1) + j * (j - 1) + k * (k - 1) + l * (l - 1) >> 1 >= least)
trans(ans, dp[i][j][k][l][lst]);
printf("%d\n", ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现