「HGOI#2019.4.19省选模拟赛」赛后总结

t1-Painting

这道题目比较简单,但是我比较弱就只是写了一个链表合并和区间DP。
别人的贪心吊打我的DP,嘤嘤嘤。

#include <bits/stdc++.h>
#define ll long long 
using namespace std;
namespace chhokmah {
#define N 100005
#define M 5005
int a[N], l[M], r[M], pos[N];
int n, m, cnt; 
ll sum[M], f[M][M];
ll ans = 0;
ll calc(int cnt) {
    for (int i = 1; i <= cnt; i ++) sum[i] += sum[i - 1];
    for (int i = cnt; i; i --) 
        for (int j = i; j <= cnt; j ++) 
            f[i][j] = max(f[i][j - 1], f[i + 1][j]) + sum[j] - sum[i - 1]; 
    return f[1][cnt];
}
void chhokmah() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i ++) scanf("%d", &a[i]);
    for (int i = 1; i <= n; i ++) r[a[i]] = i;
    for (int i = n; i; i --) l[a[i]] = i; 
    for (int i = 1; i <= m; i ++) pos[l[i]] = i; 
    for (int i = 1; i <= n; i ++) {
        if (pos[i]) {
            int cnt = 0, x = i; 
            while (pos[x]) { int y = pos[x]; pos[x] = 0; sum[++ cnt] = r[y] - l[y] + 1; x = r[y] + 1; } 
            ans += calc(cnt);  
        }
    }
    cout << ans << endl; 
} }
int main() { chhokmah::chhokmah(); return 0; }

t2-Path

很显然是一道期望\(DP\)。这一道题目还是\(Bluesky\)大佬教我做的,先%为敬。
考虑到最优的策略,一定是从当前算出期望概率较小的点来更新较大的点。


以下是\(BlueSky\)大佬的题解
考虑是按照最优策略进行移动,如果开放一条边且子节点不会使答案变劣,那么就一定会沿该边走向子节点,否则停留在原地。
假设对于点\(i\),不会使答案变劣的点数为\(degree_i\),那么意味着有\(degree_i\)种可能会移动,有\(m-degree_i\)种可能不移动。设点\(i\)走到\(n\)的期望距离为\(f_i\),则有

\[ \begin{array}{rrcl} &\large f_i&\large =&\large \frac{\large\sum_{v\in son}f_v+(m-degree_i)f_i}{\large m}+1\\\\ \large \Rightarrow&\large mf_i&\large =&\large \sum_{v\in son}f_v+(m-degree_i)f_i+m\\\\ \large \Rightarrow&\large degree_if_i&\large =&\large \sum_{v\in son}f_v+m\\\\ \large \Rightarrow&\large f_i&\large =&\large \frac{\large\sum_{v\in son}f_v+m}{\large degree_i}\\\\ \end{array} \]

考虑最优策略:
向期望距离尽可能小的位置移动,不会重复经过同一个位置。
反着考虑,从期望距离最小的位置倒着走,对期望距离较大的位置更新答案(即尚未经过的位置)。因为期望距离由可能转移到的位置决定,所以记下对于一个位置可能向多少个位置转移以及转移到的位置的期望距离和。总体从\(n\)出发以堆优化dijkstra的思路跑一遍即可,\(f_1\)就是所求答案。


窝也没有什么可以补充的。
可以稍微讲一下自己在理解时的一些问题。
Q:为什么公式是\(f_i= \frac{\sum_{v\in son}f_v+(m-degree_i)f_i}{ m}+1\)
A:可以理解成走的期望和不走的期望:
\(sum[i]\)\(\sum_{v\in son}f_v\)
走的概率很明显是\(\frac{degree_i}{m}\),那么走的期望就是\(\frac{sum[i]}{m}\)
考虑不走的话,一定是原先的期望上\(\times\)不走的概率。
不走的概率是\(\frac{m-degree_i}{m}\)
那么不走的期望就是\(\frac{m-degree_i}{m}\times f_i\)
因为无论走还是不走一定会消耗\(1\)的时间,那么需要\(+1\)

#include <bits/stdc++.h>
#define eps (1e-10)
#define db double 
#define ldb long double 
#define N 300005
using namespace std;
namespace chhokmah {
struct edge { int to, nt; } E[N << 1];
int H[N], num[N];
ldb f[N], sum[N];
bool vis[N];
int ecnt, n, m;
void add_edge(int u, int v) { E[++ ecnt] = (edge) {v, H[u]}; H[u] = ecnt; }
class cmp {
public: 
    bool operator() (int i, int j) {
        if (fabs(f[i] - f[j]) < eps) return i < j;
        else return f[i] < f[j];
    }
};
set <int, cmp> now; 
set <int, cmp> :: iterator it;
void chhokmah() {
    scanf("%d%d", &n, &m);
    for (int i = 1, u, v; i <= m; i ++) scanf("%d%d", &u, &v), add_edge(u, v), add_edge(v, u);
    f[n] = 0; now.insert(n); 
    for (int i = 1; i <= n; i ++) {
        if (now.empty()) break;
        it = now.begin(); int u = (*it); vis[u] = 1; now.erase(u);
        for (int e = H[u]; e; e = E[e].nt) {
            int v = E[e].to; 
            if (!vis[v]) {
                now.erase(v); num[v] ++;
                sum[v] += f[u];
                f[v] = (sum[v] + m) / num[v]; 
                now.insert(v);
            }
        }
    }
    printf("%0.10f\n", (db) f[1]);
}
}
int main() { chhokmah::chhokmah(); return 0; }

t3-Tree

毒瘤,做不出来。。。
贴一下标称:

#include <stdlib.h>
#include <string.h>
#include <cstdio>
#include <vector>
#include <algorithm>
#define pb push_back
#define sz(a) ((int) (a).size())
using namespace std;
const int N = (int) 3e5;
vector<int> adj[N], who[N], bad[N], path, relax[N];
int n, u, v, root, ans[N], depth[N], h[N], used[N], value[N], it, tlmx[4 * N], trmx[4 * N];

void update(int t, int l, int r, int x, int y) {
    if (l == r - 1)
        tlmx[t] = y, trmx[t] = y + 1;
    else {
        int m = (l + r) / 2;
        if (x < m) update(t * 2 + 1, l, m, x, y);
        else update(t * 2 + 2, m, r, x, y);
        tlmx[t] = max(tlmx[t * 2 + 1], (m - l) + tlmx[t * 2 + 2]);
        trmx[t] = max(trmx[t * 2 + 2], trmx[t * 2 + 1] + (r - m));
    }
}

int get_right(int t, int l, int r, int who, int k) {
    if ((l > who) || (trmx[t] + who - r <= k)) return -1;
    if (l == r - 1) return l;
    int m = (l + r) / 2;
    int rvalue = get_right(t * 2 + 2, m, r, who, k);
    if (rvalue != -1) return rvalue;
    return get_right(t * 2 + 1, l, m, who, k);
}

void get_left(int t, int l, int r, int x, int k, int &lmx, int &res) {
    if (l >= x + 1) return;
    if (r <= x + 1) {
        if (max(tlmx[t], r - l + lmx) < k) {
            lmx = max(tlmx[t], r - l + lmx);
            return;
        } else if (l == r - 1) {
            res = l;
            return;
        }
    }
    int m = (l + r) / 2;
    get_left(t * 2 + 2, m, r, x, k, lmx, res);
    if (res == -1) get_left(t * 2 + 1, l, m, x, k, lmx, res);
}

void set_value(int depth, int nvalue) {
    update(0, 0, h[root] + 1, depth, nvalue);
    value[depth] = nvalue;
}

void update_answer(int k, int who) {
    int marked = get_right(0, 0, h[root] + 1, who, k), lmx = -1, res = -1;
    if (marked == -1) return;
    get_left(0, 0, h[root] + 1, marked, k, lmx, res);
    if (res == -1) res = 0;
    if (value[res] <= k) relax[path[res]].pb(k);
    else bad[path[res]][k] = max(bad[path[res]][k], lmx + 1);
}

void dfs(int v) {
    path.pb(v);
    int mx_u = -1, pre_mx_u = -1;
    for (int i = 0; i < sz(adj[v]); ++i) {
        int u = adj[v][i];
        if ((mx_u == -1) || (h[mx_u] < h[u])) pre_mx_u = mx_u, mx_u = u;
        else if ((pre_mx_u == -1) || (h[pre_mx_u] < h[u])) pre_mx_u = u;
    }
    bad[v] = vector<int>((pre_mx_u == -1) ? 1 : (1 + h[pre_mx_u]), 0);
    for (int i = 0; i < sz(adj[v]); ++i) {
        int u = adj[v][i];
        set_value(depth[v], (u == mx_u) ? ((pre_mx_u == -1) ? 0 : (h[pre_mx_u] + 1)) : (h[mx_u] + 1));
        dfs(u);
    }
    if (mx_u != -1) {
        who[v].swap(who[mx_u]), ++it;
        for (int i = 0; i < sz(adj[v]); ++i) {
            int u = adj[v][i];
            if (mx_u == u) continue;
            used[h[u] + 1] = it;
            for (int k = 0; k <= h[u]; ++k)
                who[v][k] = min(who[v][k], who[u][k]);
        }
        for (int k = 0, mx = 0; k <= ((pre_mx_u == -1) ? -1 : h[pre_mx_u]); ++k) {
            if (used[k] == it) mx = k;
            set_value(depth[v], max(mx, bad[v][k]));
            update_answer(k, who[v][k]);
        }
    }
    who[v].pb(depth[v]);
    set_value(depth[v], 0);
    relax[v].pb(h[v]);
    for (int i = 0; i < sz(relax[v]); ++i) {
        int k = relax[v][i];
        ans[k]++, who[v][k] = depth[v];
        update_answer(k, depth[v]);
    }
    path.pop_back();
}

void calc_h(int v, int p = -1) {
    for (int i = sz(adj[v]) - 1; i >= 0; --i) {
        int u = adj[v][i];
        if (u == p) {
            swap(adj[v][i], adj[v].back());
            adj[v].pop_back();
        } else {
            depth[u] = depth[v] + 1;
            calc_h(u, v);
            h[v] = max(h[v], h[u] + 1);
        }
    }
}

int main() {
    scanf("%d", &n);
    for (int i = 0; i + 1 < n; ++i) {
        scanf("%d%d", &u, &v), --u, --v;
        adj[u].pb(v), adj[v].pb(u);
    }
    root = 0;
    calc_h(root);
    for (int i = 0; i < n; i ++) cout <<  
    dfs(root);
    for (int d = h[root] + 1; d <= n; ++d)
        ans[d] = 1;
    for (int k = 1, d = n; k <= n; ++k) {
        while ((d > 0) && (ans[d - 1] <= k)) --d;
        printf("%d%c", d, " \n"[k == n]);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/chhokmah/p/10735488.html
今日推荐