智算之道初赛第三场 - 高校组 题解

1. 水杯

在这里插入图片描述

签到题

code

#include <cstdio>
using namespace std;
typedef long long ll;
int main()
{
#ifdef LZH_LOCAL
    freopen("in.in", "r", stdin);
    // freopen("out.out", "w", stdout);
#endif
    int n, L, A, B;
    scanf("%d%d%d%d", &n, &L, &A, &B);
    int v = 0, w = -1000;
    while (n--)
    {
        int a, x;
        scanf("%d", &a);
        if (a == 1)
        {
            scanf("%d", &x);
            w = x;
        }
        else if (a == 2)
        {
            scanf("%d", &x);
            v = x;
        }
        else
        {
            if (v >= L && w >= A && w <= B)
                printf("%d\n", w);
            else
                puts("GG");
        }
    }
    return 0;
}

2. 鳖

在这里插入图片描述
模拟题。a[i]、b[j] 两个数组记下Alice和Bob的所有牌,aa[i]、bb[j] 数组标记牌在不在手上,ma[x]、mb[y] 标记牌面=x或y 的牌的上一张的位置,也可以用map标记,然后模拟摸牌即可。

code

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
int a[N * 2], b[N * 2];
bool aa[N * 2], bb[N * 2];
bool ma[N * 2], mb[N * 2]; //ma[x] = 1/0 表示 A 手上有没有 x 这个牌
int main()
{
#ifdef LZH_LOCAL
    freopen("in.in", "r", stdin);
    // freopen("out.out", "w", stdout);
#endif
    int n;
    scanf("%d", &n);
    int ta = 1, tb = 1;
    int suma = 0, sumb = 0;
    for (int i = 1; i <= 4 * n - 2; i++)
    {
        int x;
        scanf("%d", &x);
        if (i & 1)
        {
            a[ta] = x;
            if (ma[x])
            {
                aa[ma[x]] = 1;
                aa[ta] = 1;
                ma[x] = 0;
                suma--;
            }
            else
            {
                ma[x] = ta;
                suma++;
            }
            ta++;
        }
        else
        {
            b[tb] = x;
            if (mb[x])
            {
                bb[mb[x]] = 1;
                bb[tb] = 1;
                mb[x] = 0;
                sumb--;
            }
            else
            {
                mb[x] = tb;
                sumb++;
            }
            tb++;
        }
    }
    int i = 0, j = 0;
    int cnt = 0;
    while (suma && sumb)
    {
        cnt++;
        if (cnt & 1)
        {
            // Alice摸对方的第一张牌
            for (j = j + 1; j < tb; j++)
                if (!bb[j])
                    break;
            a[ta] = b[j];
            sumb--;
            mb[b[j]] = 0;
            bb[j] = 1;
            if (ma[a[ta]])
            {
                aa[ma[a[ta]]] = 1;
                aa[ta] = 1;
                ma[a[ta]] = 0;
                suma--;
            }
            else
            {
                ma[a[ta]] = ta;
                suma++;
            }
            ta++;
        }
        else
        {
            // Bob摸对方的第一张牌
            for (i = i + 1; i < ta; i++)
                if (!aa[i])
                    break;
            b[tb] = a[i];
            suma--;
            ma[a[i]] = 0;
            aa[i] = 1;
            if (mb[b[tb]])
            {
                bb[mb[b[tb]]] = 1;
                bb[tb] = 1;
                mb[b[tb]] = 0;
                sumb--;
            }
            else
            {
                mb[b[tb]] = tb;
                sumb++;
            }
            tb++;
        }
    }
    printf("%d\n", cnt);
    return 0;
}

3. 顺序安排

在这里插入图片描述
这题自己直觉可能有两种情况排列
在这里插入图片描述
然后考虑怎么把答案计算出来,求出每棵子树的结点个数,然后枚举所有结点,把该节点所有的儿子节点的子树大小排序,计算所有儿子到父亲节点对答案的贡献。
此题解释可参考这篇博客

code

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 5;
template <typename T>
void read(T &t)
{
    t = 0;
    T f = 1;
    char ch = getchar();
    while (!isdigit(ch))
    {
        if (ch == '-')
            f *= -1;
        ch = getchar();
    }
    while (isdigit(ch))
    {
        t = t * 10 + ch - 48;
        ch = getchar();
    }
    t *= f;
}
int cnt[maxn];
vector<int> v[maxn], p;
// 求子树结点的个数
void dfs(int u)
{
    cnt[u] = 1;
    int t = v[u].size();
    for (int i = 0; i < t; i++)
    {
        int e = v[u][i];
        dfs(e);
        cnt[u] += cnt[e];
    }
}
bool cmp(int a, int b) { return cnt[a] < cnt[b]; }
int main()
{
#ifdef LZH_LOCAL
    freopen("in.in", "r", stdin);
    // freopen("out.out", "w", stdout);
#endif
    int n, m;
    read(n), read(m);
    for (int i = 2; i <= n; i++)
    {
        int x;
        read(x);
        v[x].push_back(i);
    }
    dfs(1);     //求出每棵子树结点的个数 cnt[]
    ll ans = 1; //根节点1的贡献点是1
    // 分别对 每个结点作为根节点时 计算它的子节点的贡献值
    for (int i = 1; i <= n; i++)
    {
        p.clear();
        int t = v[i].size();
        for (int j = 0; j < t; j++)
            p.push_back(v[i][j]);
        // 把结点i的所有儿子结点按照子树结点个数从小到大排序
        sort(p.begin(), p.end(), cmp);
        ll temp = 1;
        // 计算结点i的子节点到i的贡献点
        t = p.size();
        for (int j = 0; j < t; j++)
        {
            int x = p[j];
            ans += temp;
            temp += cnt[x];
        }
    }
    printf("%lld\n", ans * m);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44169557/article/details/107633128