CF1800F Dasha and Nightmares
F.Dasha and Nightmares
题意:\(n\) 个字符串 \(s_i\),问有多少对不同的 \((i, j) \ (1 \le i \le j \le n)\),使得 \(s_i\) 和 \(s_j\) 拼接后的字符串满足下列条件:
- 长度为奇数
- 恰好出现 25 个字母
- 每个字母出现次数为奇数
显然,如果满足后两个条件,第一个条件也满足。
由于只与是否出现和出现次数有关,不妨用两个数 \(a_i, b_i\) 代替 \(s_i\)。
\(a\) 表示出现过哪些字符,\(b\) 表示出现过哪些次数为奇的字符。
for(char c : s) {
a[i] |= 1 << c - 'a';
b[i] ^= 1 << c - 'a';
}
如果 \(i, j\) 满足条件,则
a[i] | a[j]
恰好 25 位。a[i] | a[j] = b[i] ^ b[j]
。
枚举没出现的那一位 k,则
a[i] >> k & 1 = 0
a[j] >> k & 1 = 0
a[i] | a[j] = b[i] ^ b[j] = ((1 << 26) - 1) ^ (1 << k)
令 val = ((1 << 26) - 1) ^ (1 << k)
一个第 k 位为 0 的 a[i] 对答案的贡献是满足以下条件的 j 的个数
a[j] >> k & 1 = 0
b[j] = val ^ b[i]
用哈希表或者桶记录先前 b 出现的次数即可。
rep(k, 0, 25) {
int val = ((1 << 26) - 1) ^ 1 << k;
vector<int> t;
rep(i, 1, n) {
if(a[i] >> k & 1 ^ 1) {
++ cnt[b[i]];
t.pb(b[i]);
}
}
for(int x : t) ans += cnt[val ^ x];
for(int x : t) cnt[x] = 0;
}
我这里由于 i,j 是无序的,所以最终答案除二(自己和自己一定不行)。