codeforces 855 div3

Codeforces Round 855 (Div. 3)

1800F

题意:

给定 n 个字符串,问有多少个 {i, j} ( 1 ≤ i ≤ j ≤ n ) (1 \le i \le j \le n) (1ijn) 满足以下条件:

​ s = s i + s j s_i + s_j si+sj

  1. s 中的不同字符数exactly为 25
  2. s 中的每个字符的出现次数为 odd
题解:

转化为两个问题:

  1. 对状态进行设计使得能够直接通过 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(n226) 会炸,不可取
      • 直接将所有缺少这个字符的字符串全部存在一起,在这个区域内按照上述状态来求解
  2. 统计一个区域内呈双向一一映射的 {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();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值