本来这应该是一场 Div.4 的,但是被 tester 改成了 Div.3,于是就有了这场 8 道题的 Div.3。
比赛时只做出了 \(\text{A}\sim \text{F}\),\(\rm{G}\) 一直调不出来……
赛后找到了自己 \(\rm{G}\) 的错误,于是改一改就 A 了(
A - Minimal Square
题意简述:
找到一个面积最小的正方形,使它可以包含两个相同的边长分别为 \(a\) 和 \(b\) 的长方形。其中放置的两个长方形不能重叠。
多组测试数据。
\(\texttt{Data Range:}\ 1\le t\le 10000,\ 1\le a,\ b\le 100\)。
比较简单的题目。
容易发现正方形的边长其实就是 \(\min\{\max\{a\times 2,\ b\}, \max\{a,\ b\times 2\}\}\)。
于是直接输出面积即可。
int T, a, b;
int main()
{
T = gi();
while (T--)
{
a = gi(), b = gi();
int mx1 = min(mx1, min(max(a << 1, b), max(a, b << 1)));
cout << mx1 * mx1 << endl;
}
return 0;
}
B - Honest Coach
题意简述:
有 \(n\) 个数 \(s_i\),你需要将它们分成 \(A\)、\(B\) 两个组,且 \(A\) 和 \(B\) 中的元素个数至少为 \(1\)。
找到一个分组方案,使得 \(|\max(A) - \max(B)|\) 的值最小,其中 \(\max(A)\) 表示 \(A\) 中元素的最大值,\(\min(B)\) 表示 \(B\) 中元素的最小值。
多组测试数据。
\(\texttt{Data Range:}\ 1\le t\le 1000,\ 2\le n\le 50,\ 1\le s_i\le 1000\)。
对原数组从小到大排序,直接输出 \(\min\{s_{i+1}-s_{i}\}\)。
const int N = 53;
int T, n;
int s[N];
int main()
{
T = gi();
while (T--)
{
n = gi();
for (int i = 1; i <= n; i+=1) s[i] = gi();
sort(s + 1, s + 1 + n);
int mn = 100000000;
for (int i = 1; i < n; i+=1) mn = min(mn, s[i + 1] - s[i]);
cout << mn << endl;
}
return 0;
}
C - Similar Pairs
题意简述:
定义:一对数 \((x,\ y)\) 称为“类似的数对”,当且仅当 \(x\) 和 \(y\) 奇偶性相同或 \(|x-y|=1\)。
现给出 \(n\) 个数 \(a_i\),问能否将这些数分成 \(\frac{n}{2}\) 对“类似的数对”。能输出
YES
,否则输出NO
。多组测试数据。
\(\texttt{Data Range:}\ 1\le t\le 1000,\ 2\le n\le 50,\ 1\le a_i\le 100\),保证 \(n\) 为偶数。
首先将这些数按照奇偶性分成两组 \(v1\) 和 \(v2\)。
- 如果这两组数的大小都为偶数,那么一定有解。
- 否则:
- 如果存在 \(|v1_i - v2_j|=1\),那么我们可以先将这两个数配对,然后将剩下的书按照第一种情况配对就行了。
- 如果不存在 \(|v1_i - v2_j|=1\),那么输出无解。
int T, n;
vector <int> v1, v2;
int a[N];
int main()
{
T = gi();
while (T--)
{
n = gi();
v1.clear(), v2.clear();
for (int i = 1; i <= n; i+=1)
{
a[i] = gi();
if (a[i] & 1) v1.push_back(a[i]);
else v2.push_back(a[i]);
}
if (v1.size() % 2 == 0) {puts("YES"); continue;}
bool fl = true;
for (auto x : v1)
for (auto y : v2)
if (abs(x - y) == 1) {fl = false; break;}
if (fl) puts("NO");
else puts("YES");
}
return 0;
}
D - Buying Shovels
题意简述:
找到 \(n\) 的因数中第一个 \(\le m\) 的数 \(x\),输出 \(\frac{n}{x}\)。
多组测试数据。
\(\texttt{Data Range:}\ 1\le t\le 100,\ 1\le n, k\le 10^9\)。
直接 \(\mathcal{O}(\sqrt n)\) 求出 \(n\) 的所有因数,然后排序直接找答案。
int T, n, m;
vector <int> v;
int main()
{
T = gi();
while (T--)
{
n = gi(), m = gi();
if (m > n) {puts("1"); continue;}
v.clear();
for (int i = 1; i * i <= n; i+=1)
if (n % i == 0)
{
v.push_back(i);
if (i * i != n) v.push_back(n / i);
}
sort(v.begin(), v.end());
reverse(v.begin(), v.end());
for (auto x : v)
if (x <= m) {cout << n / x << endl; break;}
}
return 0;
}
E - Polygon
题意简述:
给出一个 \(n\times n\) 的
01
矩阵,问能否从全0
的矩阵根据如图所示的方式变成输入的矩阵。多组测试数据。
\(\texttt{Data Range:}\ 1\le t\le 1000,\ 1\le n\le 50\)。
小清新结论题。
一个矩阵有解当且仅当不会出现以下情形:
1 0
0
于是直接判断即可。
const int N = 55;
int T, n;
char s[N][N];
int main()
{
T = gi();
while (T--)
{
n = gi();
for (int i = 1; i <= n; i+=1)
scanf("%s", s[i] + 1);
bool fl = true;
for (int i = 1; i < n; i+=1)
for (int j = 1; j < n; j+=1)
if (s[i][j] == '1' && s[i + 1][j] == '0' && s[i][j + 1] == '0')
{
fl = false;
break;
}
if (fl) puts("YES");
else puts("NO");
}
return 0;
}
F - Spy-string
题意简述:
输入 \(n\) 个字符串,每个字符串的长度为 \(m\)。
问能否找到一个长度为 \(m\) 的字符串,使得它与输入的每个字符串最多有 \(1\) 个字符不同。
多组测试数据。
\(\texttt{Data Range:}\ 1\le t\le 100,\ 1\le n, m\le 10\)。
按照每一位扫描整个字符串,如果有不同的字符就依次尝试用别的字符去替代。
找到不同的字符可以用 set。
其实就是暴力枚举 + 判断。
时间复杂度约为 \(\mathcal{O}(n^4m^2\log n)\)。
const int N = 13;
int T, n, m;
string s[N];
inline bool check(string ss)
{
bool fl = true;
for (int j = 1; j <= n; j+=1)
{
int cnt = 0;
for (int k = 0; k < m; k+=1)
if (ss[k] != s[j][k])
++cnt;
if (cnt > 1) {fl = false; break;}
}
return fl;
}
bool vis[30];
int main()
{
T = gi();
while (T--)
{
n = gi(), m = gi();
for (int i = 1; i <= n; i+=1) cin >> s[i];
bool ok = false;
for (int i = 1; i <= n; i+=1)
if (check(s[i]))
{
ok = true;
cout << s[i] << endl;
break;
}
if (ok) continue;
string ans = "-1";
for (int i = 0; i < m; i+=1)
{
set <int> t[30];
set <char> ss;
int cnt = 0;
memset(vis, 0, sizeof vis);
for (int j = 1; j <= n; j+=1)
{
if (!vis[s[j][i] - 'a'])
++cnt, vis[s[j][i] - 'a'] = true;
t[s[j][i] - 'a'].insert(j);
ss.insert(s[j][i]);
}
bool fl = false;
if (cnt > 1)
{
for (int j = 1; j <= n; j+=1)
{
string now = s[j];
for (auto x : ss)
{
char bf = now[i];
now[i] = x;
if (check(now))
{
ans = now;
fl = true;
break;
}
}
if (fl) break;
}
}
if (fl) break;
}
cout << ans << endl;
}
return 0;
}
G - A/B Matrix
题意简述:
问是否存在一个 \(n\) 行 \(m\) 列的
01
矩阵,使得每一行有 \(a\) 个1
,每一列有 \(b\) 个0
。多组测试数据。
\(\texttt{Data Range:}\ 1\le t\le 1000,\ 1\le b\le n \le 50,\ 1\le a\le m \le 50\)。
一种类似于轮换的构造方式。
思维比较巧妙,但比赛时没搞出来。
const int N = 103;
int T, n, m, a, b;
string s[N];
int main()
{
T = gi();
while (T--)
{
n = gi(), m = gi(), a = gi(), b = gi();
if (a * n != b * m)
{
puts("NO");
continue;
}
for (int i = 1; i <= n; i+=1) s[i] = "";
for (int i = 1; i <= n; i+=1)
for (int j = 1; j <= m; j+=1)
s[i] += "0";
int nowl = 0;
for (int i = 1; i <= n; i+=1)
{
for (int j = nowl, cnt = 1; cnt <= a; (j += 1) %= m, cnt+=1)
s[i][j] = '1';
nowl = (nowl + a) % m;
}
puts("YES");
for (int i = 1; i <= n; i+=1)
cout << s[i] << endl;
}
return 0;
}
H - Binary Median
挖坑待填。