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 是无序的,所以最终答案除二(自己和自己一定不行)。

posted @ 2024-02-01 11:19  Lu_xZ  阅读(2)  评论(0编辑  收藏  举报