CF1679E Typical Party in Dorm
Typical Party in Dorm
题面描述
给定一个长度为
Solution
注意到字符集大小
暴力枚举串的回文中心,这里仅讨论长度为奇数的情况,偶数同理。
不难发现,当确定了一个区间过后,字符集中需要含有的字符状态是确定的,所以只需要关心不在这个区间内的问号会对答案产生什么贡献。
设总共的问号个数为
- 两侧均不为问号,且两个字符不同。此时直接退出即可。
- 两侧均为问号,此时只需要确定一个问号另一个问号也随之确定,因此只需要
加 。 - 一侧为问号,一侧为字符,此时问号确定,将
加 ,并将这个字符加入到 中。
考虑如何统计贡献。显然确定的问号不会对答案产生贡献,而未确定的问号每个都会对答案产生
注意到
时间复杂度
Code
int N;
char str[_N];
mint f[_M][20];
void init() {
int tot = 0;
For(i, 1, N) tot += str[i] == '?';
For(i, 1, N) {
auto solve = [&tot](int l, int r) -> void {
int cnt = tot, sta = 0;
while (l >= 1 && r <= N) {
if (str[l] != '?' && str[r] != '?' && str[l] != str[r]) break;
if (str[l] != '?' && str[r] == '?') sta |= 1 << (str[l] - 'a');
if (str[l] == '?' && str[r] != '?') sta |= 1 << (str[r] - 'a');
if (l != r && (str[l] == '?' || str[r] == '?')) --cnt;
For(j, 1, 17) f[sta][j] += mint(j).pow(cnt);
--l, ++r;
}
};
solve(i, i), solve(i, i + 1);
}
int lim = 1 << 17;
For(t, 1, 17) {
for (int i = 1; i < lim; i <<= 1)
for (int j = 0; j < lim; j += i << 1)
For(k, 0, i - 1) f[j+k+i][t] += f[j+k][t];
}
}
signed main() {
cin.tie(0)->sync_with_stdio(0);
cin >> N;
For(i, 1, N) cin >> str[i];
init();
int Q; cin >> Q;
while (Q--) {
string s; cin >> s;
int sta = 0;
for (char c: s) sta |= 1 << (c - 'a');
cout << f[sta][s.length()] << '\n';
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步