码迷,mamicode.com
首页 > 其他好文 > 详细

Educational Codeforces Round 49 (Rated for Div. 2)

时间:2019-12-03 23:20:06      阅读:94      评论:0      收藏:0      [点我收藏+]

标签:成长   mouse   rect   first   namespace   max   cto   class   回溯   

C - Minimum Value Rectangle

题意:给n根木棒,选4根组成长方形,使得这个长方形的周长的平方比上其面积最小。

题解:对那个式子求导,发现对于同一个长来说,是长和宽越接近,上式越小。那么排序之后每个和他附近的一个组装一下就行了。

map<int, int> m;
vector<int> v;

void test_case() {
    int n;
    scanf("%d", &n);
    m.clear();
    for(int i = 1; i <= n; ++i) {
        int ai;
        scanf("%d", &ai);
        m[ai]++;
    }
    v.clear();
    for(auto &j : m) {
        if(j.second == 2 || j.second == 3)
            v.push_back(j.first);
        else if(j.second >= 4) {
            printf("%d %d %d %d\n", j.first, j.first, j.first, j.first);
            return;
        }
    }
    ll fz, fm, a, b;
    n = v.size();
    for(int i = 0; i < n - 1; ++i) {
        ll nfz = 2ll * (v[i] + v[i + 1]);
        nfz *= nfz;
        ll nfm = 1ll * v[i] * v[i + 1];
        if(i == 0 || nfz * fm < fz * nfm) {
            a = v[i];
            b = v[i + 1];
            fz = nfz;
            fm = nfm;
        }
    }
    printf("%lld %lld %lld %lld\n", a, a, b, b);
}

事实上可能不需要map,直接来一波快排,然后跑一遍nxt。

int a[1000005];
int b[1000005];
 
void test_case() {
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    sort(a + 1, a + 1 + n);
    int w, h, btop = 0;
    for(int i = 1, nxt; i <= n; i = nxt) {
        for(nxt = i + 1; nxt <= n && a[nxt] == a[i]; ++nxt);
        int cnt = nxt - i;
        if(cnt >= 4) {
            printf("%d %d %d %d\n", a[i], a[i], a[i], a[i]);
            return;
        }
        if(cnt >= 2)
            b[++btop] = a[i];
    }
    ll fz, fm;
    for(int i = 1; i < btop; ++i) {
        ll nfz = 2ll * (b[i] + b[i + 1]);
        nfz *= nfz;
        ll nfm = 1ll * b[i] * b[i + 1];
        if(i == 1 || nfz * fm < fz * nfm) {
            w = b[i];
            h = b[i + 1];
            fz = nfz;
            fm = nfm;
        }
    }
    printf("%d %d %d %d\n", w, w, h, h);
}

D - Mouse Hunt

题意:有n个房间,有1个老鼠,开始可能在任意一个房间,在第i个房间放陷阱花ci,老鼠在第i个房间下一次就会到ai。求最便宜的陷阱总额。

题解:基环树的内向树。乱搞一点直接套Kosaraju缩点,然后缩点之后的代表点放这堆点的最小值,然后把所有0出度的ci加起来。

不过这个跟反图没有任何关系,加边然后去重甚至都不需要加边和去重直接统计出度(因为0始终是0,非0的出度去重后出度也不会是0)。

namespace SCC {
    const int MAXN = 2e5;

    int n;
    vector<int> G[MAXN + 5], BG[MAXN + 5];

    int c1[MAXN + 5], cntc1;
    int c2[MAXN + 5], cntc2;
    int s[MAXN + 5], cnts;

    int n2;
    vector<int> V2[MAXN + 5];
    //vector<int> G2[MAXN + 5], BG2[MAXN + 5];

    const int INF = 0x3f3f3f3f;
    int C1[MAXN + 5], C2[MAXN + 5];

    void Init(int _n) {
        n = _n;
        cntc1 = 0, cntc2 = 0, cnts = 0;
        for(int i = 1; i <= n; ++i) {
            G[i].clear();
            BG[i].clear();
            c1[i] = 0;
            c2[i] = 0;
            s[i] = 0;
            V2[i].clear();
            //G2[i].clear();
            //BG2[i].clear();

            C2[i] = INF;
        }
        for(int i = 1; i <= n; ++i)
            scanf("%d", &C1[i]);
        for(int i = 1, v; i <= n; ++i) {
            scanf("%d", &v);
            G[i].push_back(v);
            BG[v].push_back(i);
        }
    }

    /*void AddEdge(int u, int v) {
        G[u].push_back(v);
        BG[v].push_back(u);
    }*/

    void dfs1(int u) {
        c1[u] = cntc1;
        for(int v : G[u]) {
            if(!c1[v])
                dfs1(v);
        }
        s[++cnts] = u;
    }

    void dfs2(int u) {
        V2[cntc2].push_back(u);
        C2[cntc2] = min(C2[cntc2], C1[u]);
        c2[u] = cntc2;
        for(int v : BG[u]) {
            if(!c2[v])
                dfs2(v);
        }
    }

    void Kosaraju() {
        for(int i = 1; i <= n; ++i) {
            if(!c1[i]) {
                ++cntc1;
                dfs1(i);
            }
        }

        for(int i = n; i >= 1; --i) {
            if(!c2[s[i]]) {
                ++cntc2;
                dfs2(s[i]);
            }
        }
    }

    /*void Build() {
        n2 = cntc2;
        for(int i = 1; i <= n2; ++i) {
            for(auto u : V2[i]) {
                for(auto v : G[u]) {
                    if(c2[v] != i) {
                        G2[i].push_back(c2[v]);
                        BG2[c2[v]].push_back(i);
                    }
                }
            }
        }

        for(int i = 1; i <= n2; ++i) {
            sort(G2[i].begin(), G2[i].end());
            G2[i].erase(unique(G2[i].begin(), G2[i].end()), G2[i].end());
            sort(BG2[i].begin(), BG2[i].end());
            BG2[i].erase(unique(BG2[i].begin(), BG2[i].end()), BG2[i].end());
        }
    }*/

    void Solve() {
        ll ans = 0;
        n2 = cntc2;
        for(int i = 1; i <= n2; ++i) {
            bool cnt = 0;
            for(auto u : V2[i]) {
                for(auto v : G[u]) {
                    if(c2[v] != i) {
                        cnt = 1;
                        break;
                    }
                }
                if(cnt)
                    break;
            }
            if(!cnt)
                ans += C2[i];
        }
        printf("%lld\n", ans);
    }
}

void test_case() {
    int n;
    scanf("%d", &n);
    SCC::Init(n);
    SCC::Kosaraju();
    SCC::Solve();
}

要是真按基环树去做,是不是要从入度0的点一个一个dfs下去找环,然后有环回溯的时候顺带找一波最小值?老套路用个全局变量记录重复点的id,直到回溯到它都标记为环。注意dfs的时候要染色,遇到其他颜色dfs过的就直接退出。不过我这不是有现成的缩点模板吗?

Educational Codeforces Round 49 (Rated for Div. 2)

标签:成长   mouse   rect   first   namespace   max   cto   class   回溯   

原文地址:https://www.cnblogs.com/KisekiPurin2019/p/11979991.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!