2022牛客暑期多校训练营10(FHI)

个人题解,非广告
题集链接

F Shannon Switching Game?

博弈论

思路

从结束点开始向外考虑,结束点我们认为是必胜点,考虑其他点如何成为必胜点:

如果某点存在两条(可重)边连接至另一个必胜点,则认为该点也是必胜点;

以终点开始进行bfs寻找必胜点即可;

代码
#include <bits/stdc++.h>

using namespace std;

int win[110];
int vis[110];
vector<int> E[110];

void bfs(int x)
{
    queue<int> que;
    que.push(x);
    win[x] = 1;
    while (!que.empty())
    {
        int y = que.front();
        que.pop();

        for (int ty : E[y])
        {
            if (win[ty])
                continue;
            vis[ty]++;
            if (vis[ty] == 2)
            {
                win[ty] = 1;
                que.push(ty);
            }
        }
    }
}

int main()
{
    cin.tie(0)->sync_with_stdio(false);
    int s, t;
    int T;
    cin >> T;
    while (T--)
    {
        int n, m;
        cin >> n >> m >> s >> t;
        for (int i = 1; i <= n; i++)
        {
            vis[i] = 0;
            win[i] = 0;
            E[i].clear();
        }
        for (int i = 0; i < m; i++)
        {
            int u, v;
            cin >> u >> v;
            E[u].push_back(v);
            E[v].push_back(u);
        }
        bfs(t);
        if (win[s])
            cout << "Join Player\n";
        else
            cout << "Cut Player\n";
    }
}

H Wheel of Fortune

概率期望

思路

假设 a,b 分别为 A,B 的最大受击数, t a t_a ta 表示 a 胜利的期望量(方案数*方案对应概率),则有
t a = ∑ i = 1 a − 1 C i + b − 1 i ( 1 2 ) i + b t_a=\sum_{i=1}^{a-1}C_{i+b-1}^i(\frac 12)^{i+b} ta=i=1a1Ci+b1i(21)i+b

代码

队友代码如下

#include <iostream>

using namespace std;

const int MOD = 998244353;

long long Q_power(long long a, long long b = MOD - 2)
{
    long long res = 1;
    while (b)
    {
        if (b & 1)
            res = res * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return res;
}

const int N = 2e6 + 10;

long long Fact[N];
long long InvF[N];
long long tw[N];

void init()
{
    Fact[0] = 1;
    for (int i = 1; i < N; i++)
    {
        Fact[i] = Fact[i - 1] * i % MOD;
    }

    InvF[N - 1] = Q_power(Fact[N - 1]);

    for (int i = N - 2; i >= 0; i--)
    {
        InvF[i] = InvF[i + 1] * (i + 1) % MOD;
    }

    tw[N - 1] = Q_power(Q_power(2 , N - 1));
    for (int i = N - 2 ; i >= 0 ; i -- ) {
        tw[i] = tw[i + 1] * 2;
        if(tw[i] >= MOD) tw[i] -= MOD;
    }
}

long long C(int n, int m)
{
    if (n < m)
        return 0;
    return Fact[n] * InvF[m] % MOD * InvF[n - m] % MOD;
}

int main()
{
    init();
    int a, b;
    cin >> a;
    a = (a - 1) / 10 + 1;
    for (int i = 0; i < 7; i++)
        cin >> b;
    cin >> b;
    b = (b - 1) / 10 + 1;

    long long A, B;
    A = B = 0;
    for (int i = 0; i < a; i++)
    {
        A += C(i + b - 1, i) * tw[i+b] % MOD;
        if (A >= MOD)
            A -= MOD;
    }
//     for (int i = 0; i < b; i++)
//     {
//         B += C(i + a - 1, i) * tw[i+a] % MOD;
//         if (B >= MOD)
//             B -= MOD;
//     }

    cout << A << endl;

    return 0;
}

I Yet Another FFT Problem?

思路

去掉绝对值后移项可得 a i + b l = a j + b k a_i+b_l=a_j+b_k ai+bl=aj+bk ,考虑两数之和不会超过 2e7 ,我们只需要去重后双重循环枚举两个数组的数字,记录每个和数的一组解,如果遇到当前和数已经有解,则发现答案;

存在一种特殊情况,唯一解即为 a i = a j , b k = b l a_i=a_j,b_k=b_l ai=aj,bk=bl ,在去重时会被舍弃掉,特判这种情况即可;

代码
#include <bits/stdc++.h>

using namespace std;
const int maxn = 1e7 + 7;
int n, m;
vector<int> a(maxn), b(maxn);
vector<int> mka(maxn, -1), mkb(maxn, -1);
vector<int> pa, pb;
vector<array<int, 2>> su(2 * maxn, {-1, -1});
pair<pair<int, int>, pair<int, int>> ans = {{-1, -1}, {-1, -1}};
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        if (mka[a[i]] == -1)
        {
            mka[a[i]] = i;
            pa.push_back(i);
        }
        else
        {
            ans.first.first = mka[a[i]];
            ans.first.second = i;
        }
    }
    for (int i = 1; i <= m; i++)
    {
        scanf("%d", &b[i]);
        if (mkb[b[i]] == -1)
        {
            mkb[b[i]] = i;
            pb.push_back(i);
        }
        else
        {
            ans.second.first = mkb[b[i]];
            ans.second.second = i;
        }
    }
    if (ans.first.first != -1 && ans.second.first != -1)
    {
        printf("%d %d %d %d", ans.first.first, ans.first.second, ans.second.first,
               ans.second.second);
        return 0;
    }
    for (int i : pa)
    {
        for (int j : pb)
        {
            if (su[a[i] + b[j]][0] == -1)
            {
                su[a[i] + b[j]] = {i, j};
            }
            else
            {
                printf("%d %d %d %d", su[a[i] + b[j]][0], i, j, su[a[i] + b[j]][1]);
                return 0;
            }
        }
    }
    cout << "-1\n";
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值