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\n", 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\n", b + 1, a, 1ll*1, a);
        } else {
            if (a == 1) {
                printf("-1 -1 -1 -1\n");
            } else {
                int f = 1;
                if (ca[a]) f = 0;
                if (f == 0) {
                    printf("-1 -1 -1 -1\n");
                } 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\n");
                    } 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\n", e, d, -c, f);
                        } else {
                            printf("%lld %lld %lld %lld\n", c, f, -e, d);
                        }
 
                    }
                }
            }
        }
    }
}
posted @ 2020-07-17 01:22  ccsu_zhaobo  阅读(316)  评论(2编辑  收藏  举报