zoukankan      html  css  js  c++  java
  • 2020牛客暑期多校训练营(第三场)

    2020牛客暑期多校训练营(第三场)

    E-Two Matchings

    题意:

    给你一个数组 a, 让你构造两个排列 p, q 且p与q不相同, 求, a[i] - a[p[i]]所有值的觉得值且最小。

    题解:

    仔细想一下题目中的给的条件就可以转化位 , 再一个数轴上 ,一个数与另一个数组合, 让你不重复的选n个组合

    求出每两个组合之间的距离之和的最小值。

    因为最数轴上肯定时离的近的距离最小, 然后你会发现, 4 个数选 4 个组合最小值一定时 ((a[4] - a[1]) * 2)

    同理 6 数字 选6个组合一定时 ((a[6] - a[1]) * 2) 那8 个呢?, 8个不就是两个4个嘛, 题目给的n是偶数, 那只有两种情况了, 就是4个数字一组,和6个数字一组了。

    那怎么分呢?

    如果选择贪心那么肯定是错的你不知道选几个 4,和6, 所以用dp

    (dp[i][0])表示 第i个到 i- 3选 4得到的最小值, (dp[i][1])第 i个第 i - 5选6得到的最小值。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int N = 2e5 + 7;
    int t, n;
    ll a[N], dp[N][2];
    
    int main() {
        scanf("%d", &t);
        while (t--) {
            scanf("%d", &n);
            for (int i = 1; i <= n; i++) {
                scanf("%lld", &a[i]);
                dp[i][0] = dp[i][1] = 1e12;
            }
    
            sort(a + 1, a + n + 1);
            dp[0][0] = dp[0][1] = 0;
            for (int i = 1; i <= n; i++) {
                if (i + 3 <= n) {
                    dp[i + 3][0] = min(dp[i - 1][1] + a[i + 3] - a[i], dp[i - 1][0] + a[i + 3] - a[i]);
                }
                if (i + 5 <= n) {
                
                    dp[i +5][1] = min(dp[i- 1][0] + (a[i + 5] - a[i]), dp[i -1][1] + a[i + 5] - a[i]);
                }
            }
            printf("%lld
    ", min(dp[n][0], dp[n][1]) * 2);
            
    
        }
    }
    

    G-Operating on a Graph

    题意:

    给一个图,刚开始每个点再一个集合, 有q次询问, 每次查询将当前集合相连的点加入到该集合, 问q次操作和每个点属于那个集合。

    题解:

    直接用并查集 + 链表维护,用链边可以o(1)时间合并(尾指针连接头指针)。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1e6;
    
    int head[N], top = 1, n, m, fa[N], ranks[N];
    
    list<int> q[N];
    
    queue<int>p;
    
    struct edge {
        int u, next;
    }e[2 * N];
    
    void add_edge(int u, int v) {
        e[top].u = v;
        e[top].next = head[u];
        head[u] = top++;
    }
    
    int find(int x) {
        if (x  != fa[x]) {
            return fa[x] = find(fa[x]);
        }
        return x;
    }
    
    int main() {
        int t; scanf("%d", &t);
        while (t--) {
            scanf("%d %d", &n, &m);
    
            top = 1;
            for (int i = 0; i < n; i++) {
               q[i].clear();
            }
            for (int i = 0; i < n; i++) {
                head[i] = 0;
                fa[i] = i;
                ranks[i] = 1;
                q[i].push_back(i);
            }
            for (int i = 1; i <= m; i++) {
                int u, v;
                scanf("%d %d", &u, &v);
                add_edge(u, v);
                add_edge(v, u);
            }
            int Q; scanf("%d", &Q);
     
            while (Q--) {
                int x; scanf("%d", &x);
                if (x != fa[x]) continue;
                int fx = find(x);
                int cnt = q[x].size();
                while (cnt--) {
                   
                    int cd = q[x].front();
                    q[x].pop_front();
                    p.push(cd);
                    for (int i = head[cd]; i; i = e[i].next) {
                        int to = e[i].u;
                        int fy = find(to);
                        if(fx != fy) {
                            fa[fy] = fx;
                            q[x].splice(q[x].end(), q[fy]);
                        }
                       
                    }
                }
             
    
            }
    
            for (int i = 0; i < n; i++) {
                printf("%d ", find(i));
            }
            puts("");
        }
    }
    

    F-Fraction Construction Problem

    题意:

    ​ 给你个 (a) , (b) 让你求 (frac{c}{d} - frac{e}{f} = frac{a}{b})输出 a, b。且 (b gt d , b gt f)

    如果 gcd(a, b) > 1

    ​ 一定可以构造出一组解, 设 $x = frac{a} {gcd(a, b)}, y = frac{b}{gcd(a, b)} $

    那么 (frac{x + 1}{y} - frac{1}{y} = frac{x}{y} = frac{a}{b})

    如果 gcd(a,b) == 1

    ​ 那么 可以得到 (frac{cf - ed}{df} = frac{a}{b})

    1. ​ 如果 b只有一中质因子, 即 (b = p^k)(其中 p是质数), 那么一定无解。 证明 : 如果 (b = p^k)

      ​ 那么可以得到 (df = p ^k) 可以得到 (d = p^{k - t}, f = p^{t}) 那么 (gcd(d, f) == k * p) 那么可以得到

      ​ a % (gcd(d, f)) != 0, 如果 a%gcd(d, f) == 0那么 gcd(a, b) != 1, 因为 gcd(a, b) = =1 所以成立。

      ​ 又根据扩展gcd 可得无解。

    2. 如果 b == 1无解, 因为 a > d , a > f

    3. 其它情况均有解。可以构造 f = 一种质因数的乘积, d = b / f, 那么 gcd(f, d ) == 1

      a % gcd(f, d) == 0所以可通过扩展gcd求得。

      代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
     
    const int N=2e6+7;
    int prime[N],vis[N],top=1;
     
    void Prime(){
        for(int i=2;i<N;i++){
            if(!vis[i])prime[top++]=i;
            for(int j=1;j<top&&prime[j]*i<N;j++){
                vis[i*prime[j]]=1;
                if(i%prime[j]==0)break;
     
            }
        }
    }
     
    ll a, b;
     
    ll exgcd(ll a, ll b, ll &x, ll &y)  {
        if(b == 0) {
            x = 1;
            y = 0;
            return a;
        }
        ll d = exgcd(b, a % b, x, y);
        ll t = x;
        x = y;
        y = t - (a / b) * y;
        return d;
    }
    
    int ca[N];
    
    int main() {
        int t; scanf("%d", &t);
        Prime();
        for (int i = 1; i < top; i++) {
            if (prime[i] > 2e6)break;
            ca[prime[i]] = 1;
        }
        while (t--) {
            scanf("%lld %lld", &b, &a);
            ll g = __gcd(a, b);
            if (g != 1) {
                a = a / g;
                b = b / g;
                printf("%lld %lld %lld %lld
    ", b + 1, a, 1ll*1, a);
            } else {
                if (a == 1) {
                    printf("-1 -1 -1 -1
    ");
                } else {
                    int f = 1;
                    if (ca[a]) f = 0;
                    if (f == 0) {
                        printf("-1 -1 -1 -1
    ");
                    } else {
                        ll d = 1;
                        ll f = 1;
                        ll pos = 2;
                        for (long long i = 2; i * i <= a; i++) {
                            if (a % i == 0) {
                                while(a % i == 0) d = d * i, a = a / i;
                                pos = i;
                                break;
                            }
                            
                        }
                        if (a == 1) {
                            printf("-1 -1 -1 -1
    ");
                        } else {
                            for (ll i = pos; i * i <= a; i++) {
                                if (a % i == 0) {
                                    while ( a % i == 0) f = f * i, a = a/ i;
                                }
                            }
                            if (a > 1) f = f * a;
                    
                            ll x, y;
                            exgcd(d, f, x, y);
                            ll c = x * b;
                            ll e = y * b;
                            if (c < 0) {
                                printf("%lld %lld %lld %lld
    ", e, d, -c, f);
                            } else {
                                printf("%lld %lld %lld %lld
    ", c, f, -e, d);
                            }
     
                        }
                    }
                }
            }
        }
    }
    
  • 相关阅读:
    互斥锁Mutex与信号量Semaphore的区别
    c/c++强制类型转换
    c++中的隐藏、重载、覆盖(重写)
    运算符重载详解
    类的大小
    C++ static、const和static const 以及它们的初始化
    一种隐蔽性较高的Java ConcurrentModificationException异常场景
    Java编码常见的Log日志打印问题
    Java编程常见缺陷汇总(一)
    Java字符串连接的多种实现方法及效率对比
  • 原文地址:https://www.cnblogs.com/BOZHAO/p/13326835.html
Copyright © 2011-2022 走看看