Codeforces Round 855 (Div. 3)
1800F
题意:
给定 n 个字符串,问有多少个 {i, j} ( 1 ≤ i ≤ j ≤ n ) (1 \le i \le j \le n) (1≤i≤j≤n) 满足以下条件:
s = s i + s j s_i + s_j si+sj
- s 中的不同字符数exactly为 25
- s 中的每个字符的出现次数为 odd
题解:
转化为两个问题:
-
对状态进行设计使得能够直接通过 i 得到符号条件的 j。( i 和 j 呈一一映射关系)
-
首先对于第二个条件可以想到二进制 奇数为 1, 偶数为 0,此时已可以直接得到满足条件 2 的 j
再来考虑第一个条件,直接思考最终的 s。可以枚举某一个字符不在最终的 s 中。
考虑如何第一个条件加入状态设计中。由于之前的 0 既可以表示存在大于 0 的偶数个,也可以表示 0 个,所以状态不明确。两种解决办法:
- 三进制,0:0个、1:奇数个、2:大于 0 的偶数个,但这样在寻找 j 时,极限时间复杂度达到了 O ( n ∗ 2 26 ) O(n * 2^{26}) O(n∗226) 会炸,不可取
- 直接将所有缺少这个字符的字符串全部存在一起,在这个区域内按照上述状态来求解
-
-
统计一个区域内呈双向一一映射的 {i, j} 的数量
- 用算贡献的思想,详见代码
#include <bits/stdc++.h>
#define pii pair<int, int>
#define fi first
#define se second
#define mpr(x, y) make_pair(x, y)
using namespace std;
using li = long long;
using vi = vector<int>;
signed main() {
ios::sync_with_stdio(false), cin.tie(0);
int n; cin >> n;
vector<vi> g(26);
vector<int> v_mark(n + 5);
for (int i = 1; i <= n; ++i) {
string s; cin >> s;
int tmp_mark = 0;
vector<int> cnts(26);
for (int j = 0; j < s.size(); ++j) {
int ch = s[j] - 'a';
cnts[ch]++;
}
for (int j = 0; j < 26; ++j) {
if (!cnts[j])
g[j].push_back(i);
if (cnts[j] & 1)
tmp_mark |= (1 << j);
}
v_mark[i] = tmp_mark;
}
li res = 0;
for (int i = 0; i < 26; ++i) {
map<int, int> mp;
for (int j : g[i]) {
// 以下为处理第二个问题的代码
int i_mark = v_mark[j];
mp[i_mark]++;
int j_mark = (~i_mark) & (~(1 << i)) & ((1 << 26) - 1);
res += mp[j_mark];
}
}
cout << res;
}
1800G G. Symmetree
题意:
给定一个以 1 为根的树,问该树能够通过改变子树的布局,从而成为左右对称树
题解:
如果一棵树最多只有一个同构的子树出现奇数次,其他同构子树都是偶数次,则满足条件。
用树哈希判子树同构
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define mpr make_pair
#define pb push_back
#define fi first
#define se second
#define tpi(f, i) get<i>(f)
#define all(f, a, b) f.begin() + (a), f.begin() + 1 + (b)
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long li;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<li> vl;
#define rep(i, st, ed) for (li i = (st); i <= (ed); ++i)
#define repp(i, st, ed) for (li i = (st); i < (ed); ++i)
#define per(i, st, ed) for (li i = (st); i >= (ed); --i)
using ull = unsigned long long;
mt19937_64 rnd(chrono::steady_clock::now().time_since_epoch().count());
uniform_int_distribution<ull> dist(0, ULLONG_MAX);
const ull s = dist(rnd);
inline ull xorshift(ull x) {
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
return x;
}
void solve() {
int n; cin >> n;
vector<vi> G(n + 5);
for (int i = 1; i < n; ++i) {
int x, y; cin >> x >> y;
G[x].push_back(y), G[y].push_back(x);
}
vector<bool> f(n + 5);
vector<ull> hsh(n + 5);
function<void(int, int)> dfs = [&](int u, int fa) {
ull hsh_v = s, Sum = 0;
for (int y : G[u]) {
if (y == fa)
continue;
dfs(y, u);
ull hsh_y = xorshift(hsh[y]);
hsh_v += hsh_y;
Sum ^= hsh_y;
}
hsh[u] = hsh_v;
if (!Sum)
f[u] = 1;
else {
for (int y : G[u]) {
if (y == fa)
continue;
ull hsh_y = xorshift(hsh[y]);
if (hsh_y == Sum && f[y]) {
f[u] = 1;
break;
}
}
}
};
dfs(1, 0);
cout << (f[1] ? "YES" : "NO") << '\n';
}
signed main() {
IOS;
int T; cin >> T;
while (T--) solve();
}