https://ac.nowcoder.com/acm/contest/331/F
题解:
std
引理:如果一个子矩形的字符串可以单独重组成为回文串,那么其出现奇数个的字符至多只有一个。
考虑状压数字的每一位,第i位为1表示i出现次数为奇数次。
基于上面的引理,我们可以从左到右维护矩形前缀异或和。
当子矩形异或和的二进制表示只有1个或者0个1位时,该子矩形能单独重组成为回文串。
具体做法类似于求前缀和满足条件的计数,将第一行、第二行和两行一起三种情况分开即可。
设可以选用的字符大小集为S,时间复杂度为O(S*N)或O(NlogN)O(NlogN)(不同的实现方法)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mn = 1e6 + 5;
int n;
char a[mn], b[mn];
ll ca[mn], cb[mn], c[mn];
int ha[mn], hb[mn], h[mn];
int main() {
scanf("%d", &n);
scanf("%s", a + 1);
scanf("%s", b + 1);
ll ans = 0;
ca[0] = cb[0] = c[0] = 1;
for (int i = 1; i <= n; i++) {
ha[i] = ha[i - 1] ^ (1 << (a[i] - '0'));
hb[i] = hb[i - 1] ^ (1 << (b[i] - '0'));
h[i] = h[i - 1] ^ (1 << (a[i] - '0')) ^ (1 << (b[i] - '0'));
ans += c[h[i]] + ca[ha[i]] + cb[hb[i]];
for (int j = 0; j <= 9; j++) {
ans += ca[ha[i] ^ (1 << j)] + cb[hb[i] ^ (1 << j)] +
c[h[i] ^ (1 << j)];
}
ca[ha[i]]++;
cb[hb[i]]++;
c[h[i]]++;
}
printf("%lld\n", ans);
}