1 条题解
-
0
我代码由我不由AI!!! 关于AI说我思路是错的但我最终AC这件事。事实上,我的思路的确不比标程简洁。
解题思路
处理回文,很自然地想到用双指针指一头一尾,然后往中间缩。姑且叫指前面的为 ,后面的为 。
对于 索引来说,只要我当前选的字符的字典序小于 那么对于 到 中间的位置我可以随便选任何字母,字典序一定能比 小。
但是注意:当所选字母的字典序等于 时,接下来的选择就需要受字典序限制了。但是,这也等同于直接把 去掉了,也就说不再需要考虑了。这比较像数位 。
因此,很自然地,贡献分成了两个部分:一个是没有顶到 字典序的;反之则是顶到 字典序的。
对于第一种贡献:这十分好做。 中间的 个英文字母随便选即可,但是注意回文,所以说只有一半的位置随便选,还需注意奇偶,但是不麻烦。
其中,最难的是中界处,即第二种贡献。第二种贡献需要在中界处计算,之所以叫中界处而不是中界点,就是因为中界处包含两种情况:奇、偶。当长度为奇数时,中间会剩下一个字符, 都会指在这里,偶数时中间会剩下两个字符, 分别指左、右。当然,你肯定想到了,贡献不就是
S[i] - 'A' + 1吗?没错,但是需要做修正。因为,顶着 的字典序时, 可能 这就意味着,最终不会满足字典序小。例如:
AZAA,你会发现字母Z不能选,因为不可能是AZZA。所以,你的选择只会在A ~ Y间,你的答案需要--。但是不对,例如:BABA,按理来说,最左边的B大于了最右边的A,最终答案应该--,但是有这种情况:BAAB。这是因为中间的AB把字典序掰回来了,毕竟前面的字典序最先考虑,而最前面的B反而在回文的效果下更靠后考虑了。总的来说就是,字符越前,回文越后,字符靠后,回文靠前,最终字典序是看回文靠前的。注意,如果字典序相等,那么其实是不变的。当然,如果字典序又被掰回去的话,你的答案还是需要--的。(这道题我搞了一个上午+一个下午,头都痛了!讲也很抽象,还是看代码吧......)
代码
#include <bits/stdc++.h> #define int long long using namespace std; int T = 1; const int N = 2e5 + 10; const int MOD = 998244353; int n; string s; //快速幂,帮助计算无限制时的中间26的某次方,一般来讲我是不喜欢用pow的 int FastExp(int a, int b) { if (b == 0) return 1; int res = 1; while (b) { if (b & 1) { res = (res * a) % MOD; } a = (a * a) % MOD; b >>= 1; } return res; } void Solve() { cin >> n >> s; s = " " + s; int ans = 0, sp = n % 2;//sp处理奇偶 bool flag = false; for (int i = 1, j = n; i <= j; i++, j--) { //下面这个if判断是最难懂也是最重要的 if (s[i] > s[j]) flag = true; else if (s[i] < s[j] && i != j) flag = false; if (i == j || i == j - 1) { if (s[i] >= s[j] && flag) ans--; ans = (ans + s[i] - 'A' + 1) % MOD; } else { ans = (ans + (FastExp(26, (j - i - 1) / 2 + sp) * (s[i] - 'A')) % MOD) % MOD; } } cout << ans << '\n'; } signed main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> T; while (T--) { Solve(); } return 0; }
信息
- ID
- 2404
- 时间
- 2000ms
- 内存
- 1024MiB
- 难度
- 提高
- 标签
- 递交数
- 4
- 已通过
- 1
- 上传者