zoukankan      html  css  js  c++  java
  • Manthan, Codefest 18 (rated, Div. 1 + Div. 2)

    A - Packets

    题意:给n个硬币,要求把这些硬币装在尽可能少的袋子里,并能表示出[1,n]的所有数,求袋子数。

    题解:以前没想过为什么这个东西的本质是二进制,其实“用”和“不用”就是“1”和“0”,那么要表示[1,n]的所有数肯定需要各个二进制位都至少有1个,然后剩下假如有零头就零头自己装一个。

    void test_case() {
        int n;
        scanf("%d", &n);
        int x = 1;
        while((1 << x) <= n)
            ++x;
        printf("%d
    ", x);
    }
    

    B - Reach Median

    题意:给n(n是奇数)个数,每次操作给一个数+1或者-1,求最少的操作次数使得中位数恰好为s。

    题解:排序。然后判断s是不是恰好在中位数,是则0,否则:若中位数大于s,则需要把这个数之前的比s大的数全部改成s;否则要把这个数之后的比s小的数全部改成s。可以出一个强化版。

    int a[200005];
    
    void test_case() {
        int n, s;
        scanf("%d%d", &n, &s);
        for(int i = 1; i <= n; ++i)
            scanf("%d", &a[i]);
        sort(a + 1, a + 1 + n);
        int mid = (n + 1) / 2;
        if(a[mid] == s) {
            printf("0
    ");
            return;
        } else if(a[mid] > s) {
            ll sum = 0;
            for(int i = 1; i <= mid; ++i) {
                if(a[i] > s)
                    sum += a[i] - s;
            }
            printf("%lld
    ", sum);
            return;
        } else {
            ll sum = 0;
            for(int i = mid; i <= n; ++i) {
                if(a[i] < s)
                    sum += s - a[i];
            }
            printf("%lld
    ", sum);
            return;
        }
    }
    

    C. Equalize

    题意:给定n长度的01字符串s和t,对s进行尽可能少的操作使得它变为t。一次操作的cost为:直接修改cost=1,交换i,j位置的数cost=|i-j|。

    题解:除了临位交换,其他的直接改。

    int n;
    char s[2000005];
    char t[2000005];
    
    void test_case() {
        scanf("%d%s%s", &n, s + 1, t + 1);
        int sum = 0;
        for(int i = 1; i <= n - 1; ++i) {
            if(s[i] != s[i + 1] && s[i] != t[i] && s[i + 1] != t[i + 1]) {
                ++sum;
                swap(s[i], s[i + 1]);
            } else if(s[i] != t[i]) {
                ++sum;
                s[i] = t[i];
            }
        }
        if(s[n] != t[n]) {
            ++sum;
            s[n] = t[n];
        }
        printf("%d
    ", sum);
    }
    

    D. Valid BFS?

    题意:给一棵以1为根的树,验证一个序列是不是(其中一种合法的)BFS序。

    题解:按照题目给的序列标记同一个节点各儿子的先后顺序,然后得到的BFS序必定是唯一的,再全文比较。

    int n;
    vector<int> G1[200005];
    int pos[200005];
    
    bool vis[200005];
    
    set<pii> G2[200005];
    queue<int> Q;
    
    int ans[200005];
    
    void bfs() {
        Q.push(1);
        vis[1] = 1;
        int cnt = 0;
        while(!Q.empty()) {
            int u = Q.front();
            ans[++cnt] = u;
            Q.pop();
            for(auto &i : G2[u]) {
                int v = i.second;
                if(vis[v])
                    continue;
                Q.push(v);
                vis[v] = 1;
            }
        }
        if(cnt != n) {
            puts("No");
            return;
        }
        for(int i = 1; i <= n; ++i) {
            if(ans[pos[i]] != i) {
                puts("No");
                return;
            }
        }
        puts("Yes");
    }
    
    void test_case() {
        scanf("%d", &n);
        for(int i = 1; i <= n - 1; ++i) {
            int u, v;
            scanf("%d%d", &u, &v);
            G1[u].push_back(v);
            G1[v].push_back(u);
        }
        for(int i = 1; i <= n; ++i) {
            int x;
            scanf("%d", &x);
            pos[x] = i;
        }
        for(int i = 1; i <= n; ++i) {
            for(auto v : G1[i])
                G2[i].insert({pos[v], v});
        }
        bfs();
    }
    

    E. Trips

    题意:给一个n个点m条边的无向图,每条边是依次加入的,求每次加入边后,当前的图中后能选出的最多的点,使得他们的度数都不小于k。

    题解:不知道正着能不能做,反着一定可以做,先把整个图构造出来,标记所有度数<k的点,循环删除直到剩下的点都满足度数不小于k,然后依次删除边,注意若一条边的其中一端被删除过那么就不要重复删除了。注意处理好删除点和删除边的联系就可以。

    但是真正写的时候发现联系还挺复杂的,容易把边重复删除,用set就没这个问题了。

    int n, m, k;
    int U[200005], V[200005];
    int d[200005];
    set<int> G[200005];
    
    bool vis[200005];
    int ans[200005];
    
    int cnt;
    void DeleteV(int u) {
        if(vis[u])
            return;
        vis[u] = 1;
        /*printf("delete u=%d
    ", u);
        for(int j = 1; j <= n; ++j)
            printf(" %d", d[j]);
        printf("
    ");*/
        ++cnt;
        for(auto &v : G[u]) {
            if(vis[v])
                continue;
            --d[u];
            --d[v];
            G[v].erase(u);
            if(d[v] < k)
                DeleteV(v);
        }
        G[u].clear();
    }
    
    void test_case() {
        scanf("%d%d%d", &n, &m, &k);
        for(int i = 1; i <= m; ++i) {
            int u, v;
            scanf("%d%d", &u, &v);
            U[i] = u, V[i] = v;
            G[u].insert(v);
            G[v].insert(u);
            ++d[u];
            ++d[v];
        }
        for(int i = 1; i <= n; ++i) {
            if(!vis[i] && d[i] < k)
                DeleteV(i);
        }
        for(int i = m; i >= 1; --i) {
            /*printf("i=%d
    ", i);
            for(int j = 1; j <= n; ++j)
                printf(" %d", d[j]);
            printf("
    ");*/
            ans[i] = n - cnt;
            int u = U[i], v = V[i];
            if(vis[u] || vis[v])
                continue;
            --d[u];
            --d[v];
            G[u].erase(v);
            G[v].erase(u);
            if(!vis[u] && d[u] < k)
                DeleteV(u);
            if(!vis[v] && d[v] < k)
                DeleteV(v);
        }
        for(int i = 1; i <= m; ++i)
            printf("%d
    ", ans[i]);
    }
    
  • 相关阅读:
    转贴ARM NEON 优化的例子
    GP(General-purpose Processor)与DSP的存储器结构区别
    arm中的饱和指令
    MIPS,MCPS, MHz for voice codec
    免费提供万方论文
    ARM CORTEX Ax NEON 中的加法指令
    android C编程技巧 及 C/C++开发测试(转)
    SQL Server 存储过程的经典分页 GO
    详细设计说明书大纲 GO
    正则表达式介绍 GO
  • 原文地址:https://www.cnblogs.com/KisekiPurin2019/p/12239417.html
Copyright © 2011-2022 走看看