1. 程式人生 > 實用技巧 >2020 ccpc 威海

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_{i\in{a}} \sum_{j\in{b}} \sum_{z\in{c}} dist(i, j) + dist(j, z)+ dist(i, z)}{2}\)

最後的期望就等於 \(\frac{ans}{cnta * cntb * cntc}\)

\(cnta\)表示a的數量)

等於上面的公式可以在繼續化簡得到

\((\sum_{i\in{a}} \sum_{j\in{c}} dist(i, j) ) * cntc + (\sum_{i\in{a}} \sum_{j\in c} dist(i, j)) * cntb + (\sum_{i\in{b}} \sum_{j\in{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\n", res);






}