2024 杭电多校第一场

目录

目录

博弈

传送


给一棵根为 1 的有根树,点 i 具有一个权值 Ai 。

定义一个点对的值 f(u,v)=max(Au,Av)×|Au−Av| 。

你需要对于每个节点 i ,计算 ansi=∑u∈subtree(i),v∈subtree(i)f(u,v) ,其中 subtree(i) 表示 i 的子树。

请你输出 ⊕(ansi mod 2^64) ,其中 ⊕ 表示 XOR。


满足 n≤5×105,1≤Ai≤106

用到线段树合并+权值线段树

max(Au,Av)*|Au-Av| = max(Au,Av) * max(Au,Av) - max(Au,Av) * min(Au,Av)

= max(Au,Av)^2 -Au*Av

考虑用线段树维护三个值:区间和、区间平方和、区间个数

右区间一定大于左区间,当我们算两个子树合并的贡献时,用右区间的区间平方数乘上左区间的区间个数可以得到 \sum max(Au,Av)^2 (u,v都在i子树内,且跨越i相连),  左右区间和相乘可以得到\sum (Au,Av)

如果v在u子树里,v子树的答案已经算过了,在算u时直接加上v的答案即可。

关于线段树合并+权值线段树的复杂度:

是权值线段树,总点数和n的规模相差并不大。并且合并时一般不会重复地合并某个线段树,所以我们最终增加的点数大致是nlogn级别的。这样,总的复杂度就是nlogn级别的。(摘自oiwiki)

另外注意的小点:

⊕(ansi mod 2^64) 直接用unsigned long long 自然溢出即可,mod会爆

献上调了两小时的代码一份:

#include<bits/stdc++.h>
#define int unsigned long long
using namespace std;
const int N = 2e6 + 10;
int a[N];
vector<int> to[N];
int dp[N], rt[N << 3], ls[N << 3], rs[N << 3], sz[N << 3];
int sum[N << 3], sum2[N << 3];

void update(int id) {
    sum2[id] = sum2[ls[id]] + sum2[rs[id]];
    sum[id] = sum[ls[id]] + sum[rs[id]];
    sz[id] = sz[ls[id]] + sz[rs[id]];
}
int now ;
int merge(int a, int b, int x, int y) {
    if (!a)return b;
    if (!b)return a;
    if (x == y) {
        sz[a] += sz[b];
        sum2[a] += sum2[b];
        sum[a] += sum[b];
        return a;
    }
    int mid = (x + y) >> 1;
    if (ls[a] != 0 && rs[b] != 0) {
       now += sz[ls[a]] * sum2[rs[b]] * 2ll,now -= sum[ls[a]] * sum[rs[b]] * 2ll;
    }
    if (ls[b] != 0 && rs[a] != 0) {
        now+= sz[ls[b]] * sum2[rs[a]] * 2ll, now -= sum[ls[b]] * sum[rs[a]] * 2ll;
    }
    ls[a] = merge(ls[a], ls[b], x, mid);
    rs[a] = merge(rs[a], rs[b], mid + 1, y);
    update(a);
    return a;
}

int cnt = 0;

int add(int &id, int x, int y, int co) {
    if (!id) id = ++cnt;
    if (x == y) {
        sum2[id] += co * co;
        sum[id] += co;
        sz[id]++;
        return id;
    }
    int mid = (x + y) >> 1;
    if (co <= mid) {
        ls[id] = add(ls[id], x, mid, co);
    } else {
        rs[id] = add(rs[id], mid + 1, y, co);
    }
    update(id);
    return id;
}

int ans = 0;
void dfs(int x, int f) {
    int res = 0;
    add(rt[x], 1, 1000000, a[x]);
    for (int i = 0; i < to[x].size(); i++) {
        int v = to[x][i];
        if (v == f)continue;
        dfs(v, x);
        res += dp[v];
        now = 0;
        merge(rt[x], rt[v], 1, 1000000);
        res+=now;
    }
    dp[x] = res;
    ans ^= res;
    return;
}

void solve() {
    int n;
    cin >> n;
    for (int i = 1; i <= n - 1; i++) {
        int u, v;
        cin >> u >> v;
        to[u].push_back(v);
        to[v].push_back(u);
    }
    for (int i = 1; i <= n; i++)cin >> a[i];
    dfs(1, -1);
    cout << ans << '\n';
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int _ = 1;
    while (_--) solve();
    return 0;
}

博弈

小马给出了一个可重小写字符集合 S。

Alice 初始时有空串 A,Bob 初始时有空串 B。

两人轮流等概率取出集合 S 中的一个字符 c,将它拼接到自己的字符串的后面,直至 S 为空,每个字符只能被取一次,Alice 先手。

如果最终 A 的字典序严格大于 B,则 Alice 胜利,求其获胜的概率,答案对 998244353取模。

考虑sum=\sum hi 为偶数的情况:

i)平局,所有字符都有偶数个:

A先手随便拿一个字符ai,B后手跟着拿ai,A继续拿aj,B跟着拿aj,那么平局的概率p就是\frac{sum}{sum} *\frac{a_{i}-1}{sum-1} * \frac{sum-2}{sum-2} *\frac{a_{i}-3}{sum-3}...=\frac{\left ( a_{i}-1\right )*\left ( a_{i}-3\right )*\left ( a_{i}-5\right )...}{\left ( sum-1\right )*\left ( sum-3\right )*\left ( sum-5\right )...}

ii)非平局的情况,无非胜或败,败的情况翻转一下就是胜,所以胜局的概率就是\frac{1-p}{2}

sum为奇数的情况:

i)讨论前sum-1个可以达到平局的情况,在这个情况下由于A先手,所以A必胜

     此时所有字符有且只有一个奇数a[idx],我们先将这个奇数拿出一个,然后重复上面的平局过程:

       易得p=\frac{a[idx]}{sum}\frac{\left ( a_{i}-1\right )*\left ( a_{i}-3\right )*\left ( a_{i}-5\right )... a[idx-2]*a[idx-4]...}{\left ( sum-2\right )*\left ( sum-4\right )*\left ( sum-6\right )...}

       我们可以简化计算,当拿出了奇数中的一个后,a[idx]--,sum--。(具体看代码就懂了)

ii)前sum-1个非平局的情况,无非胜或败,败的情况翻转一下就是胜,此时胜局的概率就是\frac{1-p}{2}

iii)总的来说,此时胜局的概率就是\frac{1+p}{2}

#include<bits/stdc++.h>

#define int long long
using namespace std;
typedef long long ll;
const int N = 1e7 + 10;
const int mod = 998244353;

int a[30], n, f[N];

ll poww(ll a, ll b) {

    ll t = 1;
    while (b) {
        if (b & 1)t = t * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return t;

}

void init() {

    f[1] = 1;
    for (int i = 3; i <= N - 5; i += 2) {
        f[i] = f[i - 2] * i % mod;
    }

}

void mul(int &a, int b) {
    a = ((a % mod * b % mod) + mod) % mod;
}

void solve() {
    cin >> n;
    int sum = 0, cnt = 0, idx = -1;
    char c;
    for (int i = 1; i <= n; i++) {
        cin >> c >> a[i], sum += a[i];
        if (a[i] & 1) cnt++, idx = i;
    }

    int p = 1;

    if (sum & 1) {

        if (cnt != 1) p = 0;
        else {
            mul(p, a[idx] * poww(sum, mod - 2) % mod);
            sum--;
            mul(p, poww(f[sum - 1], mod - 2));
            for (int i = 1; i <= n; i++) {
                if (i == idx) {
                    if (a[i] > 2)mul(p, f[a[i] - 2]);
                } else {
                    mul(p, f[a[i] - 1]);
                }
            }
        }

        cout << ((1 + p) % mod * poww(2, mod - 2)) % mod << '\n';

    } else {

        if (cnt != 0)p = 0;
        else {
            mul(p, poww(f[sum - 1], mod - 2));
            for (int i = 1; i <= n; i++) {
                mul(p, f[a[i] - 1]);
            }
        }

        cout << ((1 - p + mod) % mod * poww(2, mod - 2) % mod + mod) % mod;

    }

}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int _ = 1;
    init();
    cin >> _;
    while (_--) solve();
    return 0;
}
/*
1
2
a 2
c 2
332748118
 */

传送

线段树分治+可撤销并查集

学了之后发现是板子题,贴个链接https://blog.csdn.net/landexiangmz/article/details/140587889?spm=1001.2014.3001.5502

相关推荐

  1. 第一

    2024-07-21 19:14:03       15 阅读
  2. 题解|2024暑期01

    2024-07-21 19:14:03       20 阅读
  3. 题解|2023暑期03

    2024-07-21 19:14:03       19 阅读
  4. 牛客暑期第一

    2024-07-21 19:14:03       14 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-21 19:14:03       52 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-21 19:14:03       54 阅读
  3. 在Django里面运行非项目文件

    2024-07-21 19:14:03       45 阅读
  4. Python语言-面向对象

    2024-07-21 19:14:03       55 阅读

热门阅读

  1. 密码学原理精解【9】

    2024-07-21 19:14:03       13 阅读
  2. Spring中的事务详解

    2024-07-21 19:14:03       12 阅读
  3. ARM/Linux嵌入式面经(十八):TP-Link联洲

    2024-07-21 19:14:03       15 阅读
  4. Ksyusha and Chinchilla

    2024-07-21 19:14:03       18 阅读
  5. 速盾:金融行业服务器如何避免DDoS攻击?

    2024-07-21 19:14:03       15 阅读
  6. 简单介绍什么是投影仪及投影仪的工作原理

    2024-07-21 19:14:03       14 阅读
  7. websocket

    websocket

    2024-07-21 19:14:03      14 阅读
  8. 基于ListBox制作一个好看的侧边菜单导航栏

    2024-07-21 19:14:03       15 阅读
  9. org.mybatis和JDBC有什么关系?

    2024-07-21 19:14:03       17 阅读
  10. JVM调优 jstat 与 jstack

    2024-07-21 19:14:03       15 阅读