• 牛客练习赛78


    牛客练习赛78

    A CCA的词典

    签到, 注意 s[0] == s[1]

    int main() {
        IOS; cin >> n;
        multiset<string> st;
        rep (i ,1, n) {
            string s; cin >> s;
            st.insert(s);
            if (s.size() != 1 && s[0] != s[1]) swap(s[0], s[1]), st.insert(s);
        }
        cin >> m;
        rep (i, 1, m) {
            string s; cin >> s;
            cout << st.count(s) << '
    ';
        }
        return 0;
    }
    

    B CCA的搬运

    n <= 2e3, 暴力的复杂度, 签到题, 贪心模拟题意

    int n, m, _, k, cas;
    int a[N], b[N];
    ll ans, cur;
    deque<PII> c;
     
    int main() {
        IOS; cin >> n >> m;
        rep (i, 1, n) cin >> a[i];
        unordered_set<int> st;
        rep (i, 1, m) {
            cin >> b[i];
            if (st.count(b[i])) continue;
            c.push_back({a[b[i]], b[i]}); st.insert(b[i]);
        }
        rep (i, 1, m) {
            int cur = 0;
            for (auto it = c.begin(); it != c.end(); ++it) {
                if (it->se == b[i]) { c.erase(it); break; }
                cur += it->fi;
            }
            ans += cur; c.push_front({a[b[i]], b[i]});
        }
        cout << ans;
        return 0;
    }
    

    C CCA的子树

    树形dp d[i] 表示以i为根的子树中最大的权值和, f[i]表示以i为根的树的权值和

    ll a[N], d[N], f[N], ans = -2e18;
    VI h[N];
    
    void dfs(int x, int fa) {
        for (auto &y : h[x]) if (y != fa) {
            dfs(y, x);
            if (d[x] != -1e18) umax(ans, d[x] + d[y]);
            umax(d[x], d[y]); f[x] += f[y];
        }
        f[x] += a[x]; umax(d[x], f[x]);
    }
    
    int main() {
        IOS; cin >> n;
        rep (i, 1, n) cin >> a[i], d[i] = -1e18;
        rep (i, 2, n) {
            int u, v; cin >> u >> v;
            h[u].pb(v); h[v].pb(u);
        }
        dfs(1, 0);
        if (ans == -2e18) cout << "Error";
        else cout << ans;
        return 0;
    }
    

    D CCA的小球

    二项式反演

    设有m对小球颜色相同

    (g(i))表示至少有 i 对颜色相同的小球相邻的排列方案数 (g(i) = frac {C_m^i imes (n - i)!}{2^{m - i}})

    (f(i))恰有 i 对颜色相同的小球相邻的排列方案数

    注意到(g(i) = sum_{j=i}^n C_j^i imes f(i))

    由二项式反演得 (f(i) = sum_{j=i}^n (-1)^{n-j} C_j^i imes g(i))

    (ans = f(0) = sum_{j=0}^n (-1)^{n-j} C_j^0 imes frac {C_m^j imes (n - j)!} {2^{m - j}})

    ll n, m, _, k, cas;
    ll a[N], inv[N], fac[N], facinv[N], qp[N], ans;
    unordered_set<ll> st;
    
    ll C(int n, int m) { return fac[n] * facinv[m] % mod * facinv[n - m] % mod; }
    
    void init(int n) {
        qp[0] = inv[0] = inv[1] = fac[0] = fac[1] = facinv[0] = facinv[1] = 1;
        rep (i, 2, n) {
            fac[i] = fac[i - 1] * i % mod;
            inv[i] = (ll)(mod - mod / i) * inv[mod % i] % mod;
            facinv[i] = facinv[i - 1] * inv[i] % mod;
        } qp[1] = inv[2];
        rep (i, 2, n) qp[i] = qp[i - 1] * inv[2] % mod;
    }
    
    int main() {
        IOS; cin >> n; init(1e6);
        rep (i, 1, n) {
            cin >> a[i];
            if (st.count(a[i])) ++m, st.erase(st.find(a[i]));
            else st.insert(a[i]);
        }
        rep (i, 0, m)
            if (i & 1) ans = (ans - C(m, i) * fac[n - i] % mod * qp[m - i] % mod) % mod;
            else ans = (ans + C(m, i) * fac[n - i] % mod * qp[m - i] % mod) % mod;
        cout << (ans + mod) % mod;
        return 0;
    }
    

    E CCA的小球

    可以反转意味着选可以将原本不相邻得两个区间变得相邻,

    设区间内无相同的a[i], 两个相邻区间和为 x, y

    则 ans = max(x ^ y) (x & y == 0)

    怎么预处理区间和呢? 注意到每 24 个数必出现相同的 a[i] 故可暴力处理找出存在的区间的大小, 复杂度O(n * 24)

    x ^ y, 在确定 x 的情况下, 则找i的补集 ((1 << 24) - 1 ^ x) 集合内部的最大值 y,

    暴力处理集合内部不可取, 注意到

    对于每个 y 属于 (y ^ (1 << j))集合, 其中 (1 << j & y == 0), 则线性从小集合可推大集合, 复杂度为 O((1 << 24) * 24)

    最后枚举至于, 找O(1)补集内最大值即可, 复杂度 O(1 << 24)

    const int N = 1e5 + 5, M = 1 << 24;
    
    int n, m, _, k, cas;
    int a[N], ans, mx[M];
    
    int main() {
        IOS; cin >> n;
        rep(i, 1, n) {
            cin >> a[i]; mx[m = a[i]] = 1;
            per(j, i - 1, 1) if (m & a[j]) break; else m ^= a[j], mx[m] = m;
        }
        rep (i, 1, M - 1) if (mx[i]) rep (j, 0, 23) if (!(i >> j & 1)) umax(mx[i ^ 1 << j], mx[i]);
        rep (i, 1, M - 1) umax(ans, mx[i] ^ mx[M - 1 ^ i]);
        cout << ans;
        return 0;
    }
    

    CCA的序列

    设当前长度为i 以 数字k 结尾的子序列有 f[i][k] 个, 当前总的子序列有 sum[i] 个

    注意sum[0] = 1, 空串默认算一个子序列

    则当第 i 个位置添加数字 k, 则出了 j != k, f[i][j] = f[i- 1][j];

    f[i][k] = sum[i - 1] //在 i - 1 长度的所有子序列(包括空串)后添加一个数字k

    sum[i] = (sum[i - 1] - f[i - 1][k]) + sum[i - 1] = 2 * sum[i - 1] - f[i - 1][k]

    要想sum[i] 最大, 明显是添加 min(f[i - 1][k]) 的数字k, 且注意到

    f[i - 1][k] 添加 k 之后 f[i][k] = sum[i - 1], 变成了当前长度中子序列最多的数字

    即每次都是从最小直接变成最大, 所以添加 m 个数的时候是个循环, 则可用矩阵加速

    设长度为 i - 1 的状态为 $ (min_1(f[i - 1][j]), min_2(f[i - 1][j]), ..., min_k(f[i - 1][j]), sum[i - 1])$

    则通过 × 矩阵C 可获得长度为 i 的状态

    (egin{matrix} 0 & 0 & ... & 0 & 0 & -1\ 1 & 0 & ... & 0 & 0 & 0\ 0 & 1 & ... & 0 & 0 & 0\ & & ... & & & \ 0 & 0 & ... & 1 & 0 & 0\ 0 & 0 & ... & 0 & 1 & 0\ 0 & 0 & ... & 0 & 0 & 2 end{matrix})

    输出最终 sum[n + m] - 1 (减去空序列)即可

    const int N = 1e6 + 5, M = 1e2 + 5, mod = 1e9 + 7;
    
    struct Matrix {
        vector<vector<ll>> a;
        Matrix (int n, int m) { a.resize(n, vector<ll>(m, 0)); }
        Matrix operator*(Matrix& b) {
            Matrix c(a.size(), b.a[0].size());
            rep (i, 0, c.a.size() - 1) rep (j, 0, c.a[0].size() - 1) rep (k, 0, b.a.size() - 1)
                c.a[i][j] = (c.a[i][j] + a[i][k] * b.a[k][j] % mod) % mod;
            return c;
        }
    };
    
    ll n, m, _, k, cas;
    int pre[M], a[N], rk[M];
    ll f[N + M];
    
    Matrix qpow(Matrix a, ll b) {
        Matrix ans(a.a.size(), a.a[0].size());
        rep (i, 0, a.a.size() - 1) ans.a[i][i] = 1;
        for (; b; b >>= 1, a = a * a) if (b & 1) ans = ans * a;
        return ans;
    }
    
    int main() {
        IOS; cin >> n >> m >> k; f[0] = 1; Matrix b(1, k + 1), c(k + 1, k + 1);
        rep (i, 1, n) {
            cin >> a[i];
            if (pre[a[i]]) f[i] = (f[i - 1] * 2 - f[pre[a[i]] - 1] + mod) % mod;
            else f[i] = f[i - 1] * 2 % mod;
            pre[a[i]] = i;
        }
        rep (i, 1, k) rk[i] = i, c.a[i][i - 1] = 1;
        sort(rk + 1, rk + k + 1, [&](int a, int b) { return pre[a] < pre[b]; });
        rep (i, n + 1, n + k) {
            if (pre[rk[i - n]]) f[i] = (f[i - 1] * 2 - f[pre[rk[i - n]] - 1] + mod) % mod;
            else f[i] = f[i - 1] * 2 % mod;
            b.a[0][i - n - 1] = f[i - 1];
        }
        if (n + m <= n + k) return cout << (f[n + m] - 1 + mod) % mod, 0;
        b.a[0][k] = f[n + k]; c.a[0][k] = 2, c.a[k][k] = mod - 1;
        cout << ((b * qpow(c, m - k)).a[0][k] - 1 + mod) % mod;
        return 0;
    }
    
  • 相关阅读:
    GreenPlum failover,primary和mirror切换实验 -- 重要
    Greenplum 激活standby 和恢复 master 原有角色
    GreenPlum 常用命令
    Greenplum 添加mirror步骤
    PostgreSQL 多版本的实现与Innodb和oracle的差别
    Oracle 与 postgreSQL 事务处理区别(多版本与undo区别)
    服务器使用bbr加速配置
    线表之队列
    线性表之栈
    线性表之单链表
  • 原文地址:https://www.cnblogs.com/2aptx4869/p/14528754.html
Copyright © 2020-2023  润新知