2024牛客暑期多校训练营5

B. 珑

Problem

要求用形状为 1 × 2 1\times 2 1×2 2 × 1 2\times 1 2×1 的小矩形拼成大小为 n × m n\times m n×m 的大矩形。

同时可能存在以下两种限制:

  • 任意两个小矩形的短边不能相邻
  • 任意两个小矩形的长边不能相邻

每次询问给定 n , m , a , b n,m,a,b n,m,a,b ,其中 a a a 表示短边是否存在限制, b b b 表示长边是否存在限制,问是否可以做到。

数据范围: 1 ≤ n , m ≤ 1 0 9 , 0 ≤ a , b ≤ 1 1\le n,m\le 10^9,0\le a,b\le 1 1n,m109,0a,b1

Solution

首先判断要求的大矩形是否合法,即 n , m n,m n,m 中至少有一个为偶数。

特判 n = 1 , m = 2 n=1,m=2 n=1,m=2 n = 2 , m = 1 n=2,m=1 n=2,m=1 的情况,对于其他合法的大矩形再对 a , b a,b a,b 分类讨论即可。

a = 1 , b = 1 a=1,b=1 a=1,b=1 时,任何矩形都可以做到。

a = 1 , b = 0 a=1,b=0 a=1,b=0 时,此时只能将小矩形按短边拼接起来,即 n = 1   o r   m = 1 n=1\ or\ m=1 n=1 or m=1 可以做到,其余都不可以。

a = 0 , b = 1 a=0,b=1 a=0,b=1 时,此时由于短边不能拼接起来,那么除了 n = 1   o r   m = 1 n=1\ or \ m=1 n=1 or m=1 的情况,其余都可以做到。

a = 0 , b = 0 a=0,b=0 a=0,b=0 时,任何矩形都不可以做到。

时间复杂度: O ( 1 ) O(1) O(1)

Code

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 10000 + 10;
int T = 1;
void solve()
{
    int n, m, a, b;
    cin >> n >> m >> a >> b;
    if (n % 2 == 1 && m % 2 == 1)
    {
        printf("No\n");
        return;
    }
    if ((n == 1 && m == 2) || (n == 2 && m == 1))
    {
        printf("Yes\n");
        return;
    }
    if (a == 0 && b == 0)
    {
        printf("No\n");
    }
    else if (a == 1 && b == 0)
    {
        if (n == 1 || m == 1)
        {
            printf("Yes\n");
        }
        else
        {
            printf("No\n");
        }
    }
    else if (a == 0 && b == 1)
    {
        if (n == 1 || m == 1)
        {
            printf("No\n");
        }
        else
        {
            printf("Yes\n");
        }
    }
    else
    {
        printf("Yes\n");
    }
}
int main()
{
    cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}

E. 安

Problem

给定两个长度为 n n n的数组 { a } i = 1 n \{a\}_{i=1}^n {a}i=1n { b } i = 1 n \{b\}_{i=1}^n {b}i=1n,分别表示 May 和 Ray 的骑士的血量。

May 和 Ray 轮流执行操作,May 先执行,每次操作选择一个数 p p p ,并且 a p , b p > 0 a_p,b_p>0 ap,bp>0 ,然后让对方的骑士血量减一,当血量等于零时,骑士死亡。

问两者都采取最优策略时,May 的骑士存活的最大数量是多少?

数据范围: 1 ≤ n ≤ 1 0 5 , 1 ≤ a i , b i ≤ 1 0 9 1\le n\le 10^5,1\le a_i,b_i\le 10^9 1n105,1ai,bi109

Solution

对于 a i > b i a_i>b_i ai>bi 的位置,如果在上一次操作中 Ray 选择了这一位置,那么轮到 May 的时候选择相同的位置,这样就可以确保 May 的骑士存活。

对于 a i < b i a_i<b_i ai<bi 的位置,此时 Ray 的骑士存活,因为 Ray 可以按照上面的情况执行同样的操作。

对于 a i = b i a_i=b_i ai=bi 的位置,谁先在这一位置执行操作,谁的骑士存活,因为执行完操作后就会变成上述两种情况。

c n t cnt cnt 表示 a i > b i a_i>b_i ai>bi 位置的数量, n u m num num 表示 a i = b i a_i=b_i ai=bi 位置的数量,最后的答案为 c n t + ⌈ n u m 2 ⌉ cnt+\lceil \frac{num}{2}\rceil cnt+2num

时间复杂度: O ( n ) O(n) O(n)

Code

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5;
int T = 1, n;
int a[N + 5], b[N + 5];
void solve()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    for (int i = 1; i <= n; i++)
    {
        cin >> b[i];
    }
    int ans = 0, num = 0;
    for (int i = 1; i <= n; i++)
    {
        if (a[i] > b[i])
            ans++;
        if (a[i] == b[i])
            num++;
    }
    printf("%d\n", ans + (num + 1) / 2);
}
int main()
{
    cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}


H. 入

Problem

给定一个 n n n 个节点, m m m 条边的无向图,每个节点有一个值 a i a_i ai ,确保不会出现相同值。

现在有一个棋子在一个节点上,每次棋子需要移动到与该节点相邻且 a i a_i ai 最小的节点,当相邻节点的值都大于该节点的值时停止移动。

假设你可以任意确定每个节点的 a i a_i ai ,问棋子最多可以经过多少个节点?

数据范围: 1 ≤ n ≤ 40 , 1 ≤ m ≤ ( n 2 ) 1\le n\le 40,1\le m\le \binom{n}{2} 1n40,1m(2n)

Solution

数据范围很小,考虑 dfs 求解。对每一个节点选作初始点进行 dfs ,要注意在 dfs 的过程中每访问一个节点,那么上一个节点的相邻节点就都不可以访问。

可以证明这样 dfs 最坏的时间复杂度为 3 n / 3 3^{n/3} 3n/3,还有初始点需要枚举,总的时间复杂度为 n   3 n / 3 n\ 3^{n/3} n 3n/3,可以通过此题。

Code

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5;
int T = 1, n, m, vis[50], ans;
vector<int> g[50];
void dfs(int u, int fa, int cnt)
{
    vis[u]++;
    ans = max(ans, cnt);
    for (int i = 0; i < g[fa].size(); i++)
    {
        int v = g[fa][i];
        if (v != u)
            vis[v]++;
    }
    for (int i = 0; i < g[u].size(); i++)
    {
        int v = g[u][i];
        if (v != fa && !vis[v])
            dfs(v, u, cnt + 1);
    }
    for (int i = 0; i < g[fa].size(); i++)
    {
        int v = g[fa][i];
        vis[v]--;
    }
}
void solve()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        g[i].clear();
    }
    for (int i = 1; i <= m; i++)
    {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    ans = 1;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            vis[j] = 0;
        }
        dfs(i, 0, 1);
    }
    printf("%d\n", ans);
}
int main()
{
    // cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}

L. 知

Problem

给定 n n n 场比赛的获胜概率分别为 a 1 100 , a 2 100 , … , a n 100 \frac{a_1}{100},\frac{a_2}{100},\dots,\frac{a_n}{100} 100a1,100a2,,100an

每次可以选择 i   ( i < n ) i\ (i<n) i (i<n) 并且 a i < 100 , a i + 1 > 0 a_i<100,a_{i+1}>0 ai<100,ai+1>0 ,执行 a i + 1 , a i + 1 − 1 a_i+1,a_{i+1}-1 ai+1ai+11 操作。

可以执行上述操作任意次,问这 n n n 场比赛都获胜的最大概率是多少,答案先乘以 10 0 n 100^n 100n 再对 998244353 998244353 998244353 取模。

数据范围: 1 ≤ n , a i ≤ 100 1\le n,a_i\le100 1n,ai100

Solution

对于和为定值的情况,显然各个数之间越平均,累乘后的值越大。

而上述操作将使得值只能向左边分配,对于 a i < a i + 1 a_i< a_{i+1} ai<ai+1 的情况,执行完操作后,答案肯定不会变差。由于数据范围较小,直接暴力执行上述的操作即可。

时间复杂度: O ( n 2 a i ) O(n^2a_i) O(n2ai)

Code

#include <iostream>
#define ll long long
using namespace std;
const ll M = 998244353;
int T = 1, n;
ll a[110];
void solve()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    for (int i = 2; i <= n; i++)
    {
        while (1)
        {
            int pos = 1;
            for (int j = 1; j < i; j++)
            {
                if (a[pos] > a[j])
                {
                    pos = j;
                }
            }
            if (a[pos] < a[i])
            {
                a[pos]++;
                a[i]--;
            }
            else
            {
                break;
            }
        }
    }

    ll ans = 1;
    for (int i = 1; i <= n; i++)
    {
        ans = ans * a[i] % M;
    }
    printf("%lld\n", ans);
}
int main()
{
    cin >> T;
    while (T--)
    {
        solve();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值