2020 ccpc 威海

2020 ccpc 威海

G Caesar Cipher

题意:

给你n个数, 你有两种操作

1.将区间 ([l, r])的数加1, 同时在模上65536

2.询问 ([l, l + x], [r, r + x]) 问这两段区间是否一样

判断两个区间是否一样?很容易想到哈希, 对于操作如果直接取模那么就很有可能出现hash冲突, 但是如果维护一个最大值, 然后暴力修改, 然后hash值取模改成1e9 + 7就可以a了

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 5e5 + 100;

struct segment {
    ll sum, ha, maxn;
}tree[40 * N];

ll fn[N], a[N], flag[40 * N];
const ll mod = 1e9 + 7;

#define m (l + r) / 2
#define lson 2 * node
#define rson 2 * node + 1

void build(int l, int r, int node) {
    if (l == r) {
        tree[node].sum = fn[l];
        tree[node].ha = fn[l] * a[l];
        tree[node].maxn = a[l];
        return;
    }
    build(l, m, lson);
    build(m + 1, r, rson);
    tree[node].sum = tree[lson].sum + tree[rson].sum;
    tree[node].maxn = max(tree[lson].maxn, tree[rson].maxn);
    tree[node].ha = (tree[lson].ha + tree[rson].ha) % mod;
}

void push_down(int node) {
    if (flag[node]) {
        tree[lson].maxn += flag[node];
        tree[rson].maxn += flag[node];
        tree[lson].ha = (tree[lson].ha + (flag[node] % mod * tree[lson].sum % mod) % mod) % mod;
        tree[rson].ha = (tree[rson].ha + (flag[node] % mod * tree[rson].sum % mod) % mod) % mod;
        flag[lson] += flag[node];
        flag[rson] += flag[node];
        flag[node] = 0; 
    }
}

void work(int l, int r, int node) {

    if (l == r) {
        tree[node].maxn = tree[node].maxn % 65536;
        tree[node].ha = tree[node].maxn * tree[node].sum % mod;
        return;
    }  
    push_down(node);
    if (tree[lson].maxn >= 65536) {
        work(l, m, lson);
    }

    if (tree[rson].maxn >= 65536) {
        work(m + 1, r, rson);
    }
    tree[node].maxn = max(tree[lson].maxn, tree[rson].maxn);
    tree[node].ha = (tree[lson].ha + tree[rson].ha) % mod;
}

void update(int ql, int qr, int l, int r, int node) {
    if (ql <= l && qr >= r) {
        tree[node].maxn++;
        tree[node].ha = (tree[node].ha + tree[node].sum) % mod; 
        flag[node]++;

        if (tree[node].maxn >= 65536) {
            push_down(node);
            work(l, r, node);
        }
        return;
    }
    push_down(node);
    if (ql <= m) update(ql, qr, l, m, lson);
    if (qr > m) update(ql, qr, m + 1, r, rson);
    tree[node].maxn = max(tree[lson].maxn, tree[rson].maxn);
    tree[node].ha = (tree[lson].ha + tree[rson].ha) % mod;
}

ll query(int ql, int qr, int l, int r, int node) {
    if (ql <= l && qr >= r) {
        return tree[node].ha;
    }
    ll ans = 0;
    push_down(node);
    if (ql <= m) ans = (ans + query(ql, qr, l, m, lson)) % mod;
    if (qr > m) ans = (ans + query(ql, qr, m + 1, r, rson)) % mod;
    return ans;
}


int main() {
    int n, q;
    scanf("%d %d", &n, &q);
    for (int i = 1; i <= n; i++) {
        scanf("%lld", &a[i]);
    }
    fn[1] = 1; 
    for (int i = 2; i <= n + 10; i++) {
        fn[i] = fn[i - 1] * 27;
        fn[i] %= mod;
    }

    build(1, n, 1);
    while (q--) {
        int op, l, r;
        scanf("%d %d %d", &op, &l, &r);
        if (op == 1) {
            update(l, r, 1, n, 1);
        } else {
            int x; scanf("%d", &x);
            ll ha = query(l, l + x - 1, 1, n, 1);
            ll ha1 = query(r, r + x - 1, 1, n, 1);
            if (l > r) {
                int len = l - r;
                ha1 = ha1 * fn[len + 1] % mod;
            } else {
                int len = r - l;
                ha = ha * fn[len + 1] % mod;
            }
            if (ha == ha1) {
                puts("yes");
            } else {
                puts("no");
            }
        }
    }
}

C Rencontre

题意:

给你一颗树, 然后有三个人每个选择m个点最后问这三个到达某个点最短的期望是多少?

题解:

这题有个东西要知道, 假设树上有三个点 (a,b, c)那么这三个点到某点的最近距离是 (frac{1}{2}(dist(a, b) + dist(b, c) + dist(a, c))) 如果你知道这个公式那么答案不就是求

(ans = frac{sum_{iin{a}} sum_{jin{b}} sum_{zin{c}} dist(i, j) + dist(j, z)+ dist(i, z)}{2})

最后的期望就等于 (frac{ans}{cnta * cntb * cntc})(cnta)表示a的数量)

等于上面的公式可以在继续化简得到

((sum_{iin{a}} sum_{jin{c}} dist(i, j) ) * cntc + (sum_{iin{a}} sum_{jin c} dist(i, j)) * cntb + (sum_{iin{b}} sum_{jin{c}} dist(i, j) ) * cnta)

知道这个公式后就可以用dp求出 所有a到b的距离和, 所有a到c的距离和, 所有b到c的距离后。

注意爆long long

代码:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

const int N = 2e5 + 7;

ll dp[N][3], sz[N][3];

int head[N], top = 1, n, a[N], b[N], c[N], visa[N], visb[N], visc[N];

struct edge {
    int to, w, nxt;
}e[2 * N];

void add_edge(int u, int v, int w) {
    e[top].to = v;
    e[top].w = w;
    e[top].nxt = head[u];
    head[u] = top++;
}


__int128 ab = 0, ac = 0, bc = 0;
ll ma, mb, mc, sum;

void dfs(int u, int fa) {
    if (visa[u]) {
        sz[u][0] = 1;
    } 
    if (visb[u]) {
        sz[u][1] = 1;
    }
    if (visc[u]) {
        sz[u][2] = 1;
    }
    for (int i = head[u]; i; i = e[i].nxt) {
        int to = e[i].to;
        int w = e[i].w;
        if (to == fa) {
            continue;
        }
        dfs(to, u);       
        dp[u][0] += dp[to][0] + sz[to][0] * 1ll * w;
        dp[u][1] += dp[to][1] + sz[to][1] * 1ll * w;
        dp[u][2] += dp[to][2] + sz[to][2] * 1ll * w;

        sz[u][0] += sz[to][0];
        sz[u][1] += sz[to][1];
        sz[u][2] += sz[to][2];
        
    }
}

ll fn[N][3], fz[N][3];

void dfs1(int u, int fa) {

    if (visa[u]) {
        ac += fn[u][2];
        ab += fn[u][1]; 
        
    }
    if (visb[u]) {
        bc += fn[u][2];
        
    }
   

    
    for (int i = head[u]; i; i = e[i].nxt) {
        int to = e[i].to;
        int w = e[i].w;
        if (to == fa) continue;
        
        ll sb = fn[u][1] - dp[to][1] - 1ll* w * sz[to][1];
        sb = sb + w * (mb - sz[to][1]);
        fn[to][1] = sb  + dp[to][1];

        ll sc = fn[u][2] - dp[to][2] - 1ll * w * sz[to][2];
        sc = sc + w * (mc - sz[to][2]);
        fn[to][2] = sc + dp[to][2];
   
        dfs1(to, u); 

    }

}


int main() {
    scanf("%d", &n);
    for (int i = 1; i < n; i++) {
        int u, v, w;
        scanf("%d %d %d", &u, &v, &w);
        add_edge(u, v, w);
        add_edge(v, u, w);
    }

    scanf("%d", &ma);
    for (int i = 1; i <= ma; i++) {
        scanf("%d", &a[i]);
        visa[a[i]] = 1;
    }

    scanf("%d", &mb);
    for (int i = 1; i <= mb; i++) {
        scanf("%d", &b[i]);
        visb[b[i]] = 1;
    }

    scanf("%d", &mc);
    for (int i = 1; i <= mc; i++) {
        scanf("%d", &c[i]);
        visc[c[i]] = 1;
    }
    sum = ma * mb * mc;

    dfs(1, 0);
    fn[1][0] = dp[1][0];
    fn[1][1] = dp[1][1];
    fn[1][2] = dp[1][2];

    dfs1(1, 0);
 
    __int128 ans = ac * mb + bc * ma + ab * mc;
    ans = ans / 2;
    double res = (double)ans / (double)sum;

    printf("%.9f
", res);






}
原文地址:https://www.cnblogs.com/BOZHAO/p/13924817.html