[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)删除。