zoukankan      html  css  js  c++  java
  • HBCPC2021-Contest 部分题解

    C Cover Master

    题目描述

    解题思路

      我们把图中红色的区间称为关键点。可以发现树上每个关键点之间是没有祖先关系的,当两个关键点向上走到它们的lca的时候,会合并成一个点,并且向上合并的过程中,最左边的关键点和最右边的关键点一定会随之往上升。可以先用dfs把询问区间涉及的关键的点及其lca建成一棵树(大概可以称之为虚树?),然后枚举树上最左边和最右边的两个分支上的点,记录一下这些点包含多少关键点,以及他们包含的区间大小,对符合条件的结果取min即可。

    代码

    const int maxn = 2e6+10;
    const int maxm = 2e5+10;
    int idx, sz[maxn];
    ll n, L, R, k, lv[maxn], rv[maxn];
    vector<int> e[maxn], ln, rn;
    int dfs(ll l, ll r) {
        if (r<L || l>R) return 0;
        if (l>=L && r<=R) {
            ++idx; 
            lv[idx] = l, rv[idx] = r, sz[idx] = 1;
            return idx;
        }
        ll mid = (l+r)>>1;
        int x = dfs(l, mid);
        int y = dfs(mid+1, r);
        if (!x || !y) return x|y;
        else {
            ++idx;
            lv[idx] = l, rv[idx] = r, sz[idx] = sz[x]+sz[y];
            e[idx].push_back(x);
            e[idx].push_back(y);
            return idx;
        }
    }
    void dfsl(int u) {
        ln.push_back(u);
        if (e[u].empty()) return;
        dfsl(e[u][0]);
    }
    void dfsr(int u) {
        rn.push_back(u);
        if (e[u].empty()) return;
        if (e[u].size()==1) dfsr(e[u][0]);
        else dfsr(e[u][1]);
    }
    void init() {
        ln.clear(), rn.clear();
        for (int i = 0; i<=idx; ++i) {
            e[i].clear();
            lv[i] = rv[i] = sz[i] = 0;
        }
        idx = 0;
    }
    int main() { 
        IOS;
        int __; cin >> __;
        while(__--) {
            cin >> n >> L >> R >> k;
            init();
            int rt = dfs(1LL, n);
            dfsl(rt); dfsr(rt);
            if (k==1) cout << rv[rt]-lv[rt] << endl;
            else {
                ll ans = 2e18;
                for (auto u : ln)
                    for (auto v : rn)
                        if (u!=rt && v!=rt && sz[rt]-sz[u]-sz[v]+2<=k) 
                            ans = min(ans, rv[v]-lv[u]);
                cout << ans << endl;
            }
        }
        return 0;   
    }
    

    F 蒸汽朋克

    题目描述

    解题思路

      这个题题解已经说的很清楚了,就看细节处理的怎么样了,如果用double的话可能有精度问题,按照nb学弟的说法直接存储(r imes w)判断的时候就不用卡精度了。

    代码

    const int maxn = 1e5+10;
    const int maxm = 1e5+10;
    int n, m, k, vis[maxn], f[maxn];
    ll r[maxn], w[maxn], rw[maxn];
    double w2[maxn];
    vector<int> e[maxn], tmp;
    bool wok, isbg;
    void dfs(int u) {
        tmp.push_back(u);
        for (auto v : e[u]) {
            if (vis[v]) {
                if (vis[v]==vis[u]) isbg = 0;
                if (rw[u]+rw[v]!=0) wok = 0;
            }
            else {
                vis[v] = -vis[u];
                if (f[v]) {
                    if (rw[u]+rw[v]!=0) wok = 0;
                }
                else {
                    f[v] = 1;
                    w2[v] = -r[u]*w2[u]/r[v];
                    rw[v] = -rw[u];
                }
                dfs(v);
            }
        }
    }
    int main() {
        IOS; 
        cin >> n >> m >> k;
        for (int i = 1; i<=n; ++i) cin >> r[i];
        for (int i = 1, a, b; i<=m; ++i) {
            cin >> a >> b;
            e[a].push_back(b);
            e[b].push_back(a);
        }
        for (int i = 1; i<=k; ++i) {
            int num; cin >> num;
            cin >> w[num]; f[num] = 1;
            rw[num] = r[num]*w[num];
            w2[num] = w[num];
        }
        bool ok = 1;
        for (int i = 1; i<=n; ++i)
            if (f[i] && !vis[i]) {
                vis[i] = 1; 
                tmp.clear();
                isbg = wok = 1;
                dfs(i);
                if (!wok) ok = 0;
                else if (!isbg) {
                    for (auto v : tmp)
                        if (rw[v]) ok = 0;
                }
            }
        bool ok2 = 0;
        for (int i = 1; i<=n; ++i)
            if (!vis[i]) {
                vis[i] = 1; 
                tmp.clear();
                isbg = 1;
                dfs(i);
                if (isbg) ok2 = 1;
                else if (!isbg) {
                    for (auto v : tmp)
                        if (rw[v]) ok = 0;
                }
            }
        if (!ok) {
            cout << "It is not steampunk!";
            return 0;
        }
        if (ok2) {
            cout << "oo";
            return 0;
        }
        cout << "Steampunk!" << endl;
        for (int i = 1; i<=n; ++i) cout << fixed << setprecision(4) << w2[i] << (i==n ? "":" ");
        return 0;
    }
    

    L 变进制四舍五入

    题目描述

    解题思路

      这个题做的时候看样例猜到最后一步肯定是x在y进制下就1位,并且可以进到第2位,这样就变成y了。而x小于y的时候可以把x变成2x-1,但是一直没想出来在x大于y的时候怎么尽可能的把x变小,唉,还是太菜了。

    代码

    const int maxn = 2e3+10;
    const int maxm = 1e5+10;
    vector<P> ans;
    int main() {
        IOS; 
        ll x, y; cin >> x >> y;
        while(x>y) {
            ans.push_back({(x*2+2)/3, 2});
            x = (x*2+2)/3;
        }
        while(x<=y/2) {
            ans.push_back({x*2-1, 2});
            x = x*2-1;
        }
        if (x<y) ans.push_back({y, 2});
        cout << ans.size() << endl;
        for (auto v : ans) cout << v.x << ' ' << v.y << endl;
        return 0;
    }
    
  • 相关阅读:
    kali linux源大全
    kali2016.2(debian)快速安装mysql5.7.17
    hadoop java上传文件
    HDFS客户端的权限错误:Permission denied
    hadoop fs命令
    解决Unable to load native-hadoop library for your platform
    并查集。路径压缩 算法运用学习(一)
    HBase快速安装
    记一次zookeeper单机伪集群分布
    ZooKeeper使用命令大全
  • 原文地址:https://www.cnblogs.com/shuitiangong/p/15505518.html
Copyright © 2011-2022 走看看