文章目录
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 1≤n,m≤109,0≤a,b≤1
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 1≤n≤105,1≤ai,bi≤109。
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} 1≤n≤40,1≤m≤(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+1,ai+1−1 操作。
可以执行上述操作任意次,问这 n n n 场比赛都获胜的最大概率是多少,答案先乘以 10 0 n 100^n 100n 再对 998244353 998244353 998244353 取模。
数据范围: 1 ≤ n , a i ≤ 100 1\le n,a_i\le100 1≤n,ai≤100
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();
}
}