[The 2023 ICPC AROC I] I Pa?sWorD 题解
[The 2023 ICPC AROC I] I Pa?sWorD 题解
思路
朴素思路
最朴素的思路其实很简单:
设 \(f(\mathit{pos},\mathit{last},0/1,0/1,0/1)\) 表示 \(\mathit{pos}\) 位置,上一个为 \(\mathit{last}\),是否有大写字母、小写字母、数字。
用类似数位 DP 的转移方式,记忆化搜索即可。
代码:
#include <bits/stdc++.h> using namespace std; using ll = long long; using pii = pair<int, int>; const ll MOD = 998244353; #define gor(i, x) for (int i = 0; i < (x); ++i) namespace pri { const int to[256] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; }; using pri::from, pri::to; const int N = 1e5 + 10; const int D = 65; ll f[N][D][2][2][2]; inline void init(int s0) { if (islower(s0)) f[0][to[s0]][1][0][0] = 1, f[0][to[s0] + 26][0][1][0] = 1; else if (isupper(s0)) f[0][to[s0]][0][1][0] = 1; else if (isdigit(s0)) f[0][to[s0]][0][0][1] = 1; else { gor(i, 26) f[0][to[i + 'a']][1][0][0] = 1; gor(i, 26) f[0][to[i + 'A']][0][1][0] = 1; gor(i, 10) f[0][to[i + '0']][0][0][1] = 1; } } inline void do_upper(int pos, int ths) { auto &ff = f[pos][ths]; auto &f0 = f[pos - 1]; gor(a, 2) gor(c, 2) gor(j, 62) if (j != ths) (ff[a][1][c] += (f0[j][a][0][c] + f0[j][a][1][c]) % MOD) %= MOD; } inline void do_lower(int pos, int ths) { auto &ff = f[pos][ths]; auto &f0 = f[pos - 1]; gor(b, 2) gor(c, 2) gor(j, 62) if (j != ths) (ff[1][b][c] += (f0[j][0][b][c] + f0[j][1][b][c]) % MOD) %= MOD; } inline void do_digit(int pos, int ths) { auto &ff = f[pos][ths]; auto &f0 = f[pos - 1]; gor(a, 2) gor(b, 2) gor(j, 62) if (j != ths) (ff[a][b][1] += (f0[j][a][b][0] + f0[j][a][b][1]) % MOD) %= MOD; } inline void do_all(int pos, int sp) { auto &ths = to[sp]; if (islower(sp)) do_lower(pos, ths), do_upper(pos, ths + 26); else if (isupper(sp)) do_upper(pos, ths); else if (isdigit(sp)) do_digit(pos, ths); else { gor(i, 26) do_lower(pos, i); gor(i, 26) do_upper(pos, i + 26); gor(i, 10) do_digit(pos, i + 52); } } ll solve(int n, string str) { init(str[0]); for (int pos = 1; pos < n; ++pos) do_all(pos, str[pos]); ll res = 0; auto &fn = f[n - 1]; gor(i, 62) (res += fn[i][1][1][1]) %= MOD; return res; } #define fastio() ios::sync_with_stdio(false), cin.tie(nullptr) signed main() { fastio(); int n; cin >> n; string str; cin >> str; printf("%lld\n", solve(n, str)); return 0; }
数组开到了 \(10^5\times62\times8\),内存超限了,考虑滚动数组优化。
滚动数组
挺简单的,代码:
#include <bits/stdc++.h> using namespace std; using ll = long long; using pii = pair<int, int>; const ll MOD = 998244353; #define gor(i, x) for (int i = 0; i < (x); ++i) namespace pri { const int to[256] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; }; using pri::from; using pri::to; const int N = 1e5 + 10; const int D = 65; ll f[2][D][2][2][2]; inline void init(int s0) { if (islower(s0)) f[0][to[s0]][1][0][0] = 1, f[0][to[s0] + 26][0][1][0] = 1; else if (isupper(s0)) f[0][to[s0]][0][1][0] = 1; else if (isdigit(s0)) f[0][to[s0]][0][0][1] = 1; else { gor(i, 26) f[0][to[i + 'a']][1][0][0] = 1; gor(i, 26) f[0][to[i + 'A']][0][1][0] = 1; gor(i, 10) f[0][to[i + '0']][0][0][1] = 1; } } #define ff f[pos][now] #define f0 f[pos ^ 1] inline void do_lower(int pos, int now) { gor(b, 2) gor(c, 2) gor(j, 62) if (j != now) (ff[1][b][c] += (f0[j][0][b][c] + f0[j][1][b][c]) % MOD) %= MOD; } inline void do_upper(int pos, int now) { gor(a, 2) gor(c, 2) gor(j, 62) if (j != now) (ff[a][1][c] += (f0[j][a][0][c] + f0[j][a][1][c]) % MOD) %= MOD; } inline void do_digit(int pos, int now) { gor(a, 2) gor(b, 2) gor(j, 62) if (j != now) (ff[a][b][1] += (f0[j][a][b][0] + f0[j][a][b][1]) % MOD) %= MOD; } #undef ff #undef f0 #define ths to[sp] inline void do_all(int pos, int sp) { memset(f[pos], 0, sizeof f[pos]); if (islower(sp)) do_lower(pos, ths), do_upper(pos, ths + 26); else if (isupper(sp)) do_upper(pos, ths); else if (isdigit(sp)) do_digit(pos, ths); else { gor(i, 26) do_lower(pos, i); gor(i, 26) do_upper(pos, i + 26); gor(i, 10) do_digit(pos, i + 52); } } #undef ths ll solve(int n, string str) { init(str[0]); int j = 1; for (int pos = 1; pos < n; ++pos, j ^= 1) do_all(j, str[pos]); ll res = 0; gor(i, 62) (res += f[j ^ 1][i][1][1][1]) %= MOD; return res; } #define fastio() ios::sync_with_stdio(false), cin.tie(nullptr) signed main() { fastio(); int n; cin >> n; string str; cin >> str; printf("%lld\n", solve(n, str)); return 0; }
但是,时间复杂度呢?可知,总字符数 \(3\times10^5\),可用字符集大小 \(62\),总状态数 \(1.248\times10^8\),不可过。
优化
展开一下转移:
\[\begin{array}{l}
f(\mathit{pos},\mathit{this},a,b,c):\\\quad
a\rightarrow[\texttt{a},\texttt{z}],b\rightarrow[\texttt{A},\texttt{Z}],c\rightarrow[\texttt{0},\texttt{9}]\\\\
\mathit{if}\space s_{\mathit{pos}}\in[\texttt{a},\texttt{z}]\rightarrow(a=1):\\\quad
f(\mathit{pos},\mathit{this},1,b,c)=\sum_jf(\mathit{pos}-1,j,0/1,b,c)-f(\mathit{pos}-1,\mathit{this},0/1,b,c)\\\\
\mathit{if}\space s_{\mathit{pos}}\in[\texttt{A},\texttt{Z}]\rightarrow(b=1):\\\quad
f(\mathit{pos},\mathit{this},a,1,c)=\sum_jf(\mathit{pos}-1,j,a,0/1,c)-f(\mathit{pos}-1,\mathit{this},a,0/1,c)\\\\
\mathit{if}\space s_{\mathit{pos}}\in[\texttt{0},\texttt{1}]\rightarrow(c=1):\\\quad
f(\mathit{pos},\mathit{this},a,b,1)=\sum_jf(\mathit{pos}-1,j,a,b,0/1)-f(\mathit{pos}-1,\mathit{this},a,b,0/1)\\\\
\mathit{if}\space s_{\mathit{pos}}=\texttt{?}:\\
\quad\Rightarrow[\texttt{a},\texttt{z}]:\sum_{i\in[\texttt{a},\texttt{z}]}\Big(\sum_jf(\mathit{pos}-1,j,0/1,b,c)-f(\mathit{pos}-1,i,0/1,b,c)\Big)\\
\quad\Rightarrow[\texttt{A},\texttt{Z}]:\sum_{i\in[\texttt{A},\texttt{Z}]}\Big(\sum_jf(\mathit{pos}-1,j,a,0/1,c)-f(\mathit{pos}-1,i,a,0,1,c)\Big)\\
\quad\Rightarrow[\texttt{0},\texttt{9}]:\sum_{i\in[\texttt{0},\texttt{9}]}\Big(\sum_jf(\mathit{pos}-1,j,a,b,0/1)-f(\mathit{pos}-1,i,a,b,0/1)\Big)
\end{array}
\]
其实就是,对于每一个 ?
,都需要从上一维的每一个(排除三个情况)状态转移,那我们可以记录上一维的总和,转移的时候减去特殊的三个即可。
代码
本文来自博客园,作者:RainPPR,转载请注明原文链接:https://www.cnblogs.com/RainPPR/p/solution-icpc2023aroc-1i.html
如有侵权请联系我(或 2125773894@qq.com)删除。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!