Codeforces Round #644 (Div. 3) A-H 题解
题目链接: https://codeforces.com/contest/1360
A. Minimal Square
题目大题: 将长宽为a, b的两个相同矩形嵌入正方形中, 问正方形的最小面积.
解题思路: 找到长宽, 并判断两倍的宽是否大于长.
/*
* @Author: Hellcat
* @Date: 2020-05-24 23:54:16
*/
#include <bits/stdc++.h>
using namespace std;
int main() {
int T; cin>>T;
while(T--) {
int a, b; cin>>a>>b;
int Min = min(a, b);
int Max = max(a, b);
if(2*Min >= Max)
cout<<pow(2*Min, 2)<<endl;
else
cout<<pow(Max, 2)<<endl;
}
}
B. Honest Coach
题目大意: 将一个数组分为A, B两组, 使得|max(A)−min(B)|最小.
解题思路: 将数组小到大排序, 找到相邻两个元素最小的差值即为所求.
/*
* @Author: Hellcat
* @Date: 2020-05-24 23:54:16
*/
#include <bits/stdc++.h>
using namespace std;
int a[55];
int main() {
int T; cin>>T;
while(T--) {
int n; cin>>n;
for(int i = 0; i < n; i++) cin>>a[i];
sort(a, a + n);
int Min = 0x3f3f3f3f;
for(int i = 0; i < n-1; i++) {
Min = min(Min, a[i+1] - a[i]);
}
cout<<Min<<endl;
}
}
C. Similar Pairs
题目大意: 定义奇偶性相同的一对数或满足差值为1的一对数(|x−y|=1)为Similar Pairs. 输入的数组元素个数为偶数.
解题思路: 若输入的奇偶个数均为偶数, 则满足配对关系. 否则, 对数组排序后查找是否有满足差值为1的相邻元素. 如果有则满足题意, 否则不满足.
/*
* @Author: Hellcat
* @Date: 2020-05-24 23:54:16
*/
#include <bits/stdc++.h>
using namespace std;
int a[55];
int main() {
int T; cin>>T;
while(T--) {
int n; cin>>n;
int e = 0, d = 0;
for(int i = 0; i < n; i++) {
cin>>a[i];
if(a[i] & 1) d++;
else e++;
}
if((e&1) == 0) { puts("YES"); continue; }
sort(a, a+n);
int diff = 0;
for(int i = 0; i < n - 1; i++) {
diff = a[i+1] - a[i];
if(diff == 1) break;
}
if(diff == 1) { puts("YES"); continue; }
puts("NO");
}
}
D. Buying Shovels
题目大意: 买n个铁锹, 只能从给定的1~k种包装中选择一种, 全部购买这种包装的商品. 求最小购买的商品数量.
解题思路: 首先想到的是暴力枚举, 而1e9的数据量必然TLE, 随后针对暴力解法进行优化. 对特殊情况单独判定后, 结合素数判定的思路, 只要考虑前sqrt(n)的情况. 枚举2~sqrt(n)之间的数, 如果能被整除, 且满足i <= k, 则更新答案. 更新时考虑2种情况, 1)是选择包含i件商品的包裹, 购买n/i件. 2)是满足n/i <= k时选择包含n/i件商品的包裹, 购买i件. 这样一来, 时间复杂度可优化到O(logn)级别.
/*
* @Author: Hellcat
* @Date: 2020-05-24 23:54:16
* https://codeforces.com/contest/1360/problem/D
* D. Buying Shovels
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
int T; cin>>T;
while(T--) {
int n, k; cin>>n>>k;
if(k >= n) { puts("1"); continue; }
if(k == 1) { cout<<n<<endl; continue; }
int m = floor(sqrt(n) + 0.5);
int res = n;
for(int i = 2; i <= m; i++) {
if(n%i == 0 && i <= k) { res = min(res, n/i); if(n/i <= k) res = min(res, i); }
}
cout<<res<<endl;
}
}
E. Polygon
题目大意: 训练发射炮弹, 每次只能从左侧发射到右侧或上方发射到下方, 碰到1或边界为止, 然后将所在位置由0改为1. 满足这样要求的训练输出"YES". 如图所示:
解题思路: 首先想到dfs中的连通图思路, 从右侧及下方的1作为起点遍历. 最后如果没有剩下1则满足题意, 否则不满足. 而这题只有2个方向, 这样做显然有些复杂. 考虑不满足题意的情况, 必然存在一个1其左侧以及下方均为0. 遍历全图判断是否有这样的1即可. 同时注意, 在双重循环内一次break并不能完全跳出, 需要在双重循环外进行输出, 否则会出现输出多个"NO"的情况.
/*
* @Author: Hellcat
* @Date: 2020-05-25 11:44:21
*/
#include <bits/stdc++.h>
using namespace std;
char maze[55][55];
int main() {
int T; cin>>T;
while(T--) {
int n; cin>>n;
for(int i = 1; i <= n; i++) cin>>maze[i]+1;
bool flag = 1;
for(int i = 1; i < n; i++)
for(int j = 1; j < n; j++)
if(maze[i][j] == '1' && maze[i+1][j] == '0' && maze[i][j+1] == '0')
{ flag = 0; break; }
if(flag) puts("YES");
else puts("NO");
}
}
F. Spy-string
题目大意: 给出n个字符串a1, a2, …, an, 如果字符串s对每个字符串都满足不相同字符不超过一个(ai[j] ≠ s[j]的个数 < 1), 输出这样的字符串s.
解题思路: 题给数据量不大, 输入字符串个数n(1≤n≤10)和每个字符串的长度m(1≤m≤10). 字符串均由英文字符组成, 考虑暴力的解法. 由于不相同字符不超过1个, 那么将输入的第一个字符串的每个字符逐个改为'a'~'z', 再对第2~n个字符串遍历, 检查是否满足不相同字符不超过一个. 满足则输出s, 不满足输出-1.
/*
* @Author: Hellcat
* @Date: 2020-05-25 14:47:14
*/
#include <bits/stdc++.h>
using namespace std;
string s[11], res;
int n, m;
bool check() {
for(int i = 2; i <= n; i++) {
int cnt = 0;
for(int j = 0; j < m; j++) {
if(s[i][j] != res[j])
cnt++;
if(cnt > 1) return 0;
}
}
return 1;
}
void slove() {
for(int i = 0; i < m; i++) {
for(char ch = 'a'; ch <= 'z'; ch++) {
res[i] = ch;
if(check()) {
cout<<res<<endl;
return;
}
res[i] = s[1][i]; // 再改回去
}
}
puts("-1");
}
int main() {
int T; cin>>T;
while(T--) {
cin>>n>>m;
for(int i = 1; i <= n; i++) cin>>s[i];
res = s[1];
slove();
}
}
G. A/B Matrix
题目大意: 给定一个\(n×m\)的矩阵, 使得每行有a个1, 每列有b个1, 其余元素均为0.
例如n=3, m=6, a=2, b=1时, 矩阵为
解题思路: 先考虑不满足题设的情况. 对于行, 矩阵中1的个数为\(a \times n\)个, 对于列则应为\(b \times m\)个, 当\(a \times n != b \times n\)时输出NO.
其次, 将矩阵初始化为0, 考虑矩阵中如何填充1. 将题目中的样例转化为更一般的矩阵, 如:
也是满足题设条件的输出. 对于第四个样例4 4 2 2输出的矩阵, 也可以转为
多次尝试, 得到一般的规律后, 有如下思路: 单独考虑行, 在每行填充a个1, 用col维护填充的字符\(1\)的纵坐标, 根据规律只需要每次填充时++col. 同时为防止越界将col %= m即可.
/*
* @Author: Hellcat
* @Date: 2020-05-26 08:55:48
*/
#include <bits/stdc++.h>
using namespace std;
bool res[55][55];
int main() {
int T; cin>>T;
while(T--) {
memset(res, 0, sizeof res);
int n, m, a, b; cin>>n>>m>>a>>b;
if(a*n != b*m) { puts("NO"); continue; }
int col = 0; // column position
for(int i = 1; i <= n; i++)
for(int j = 1; j <= a; j++)
res[i][++col] = 1, col %= m;
puts("YES");
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++)
cout<<res[i][j];
puts("");
}
}
}
H. Binary Median
题目大意: 给定二进制字符串长度\(m\)(\(1\le m \le60\)), 按字典序生成总共\(2^m\)个长度为\(m\)的二进制字符串. 然后从中删去n个字符串, 剩下\(k=2^m-n\)个字符串. 按照字典序排列后输出第\(\lfloor \frac{k-1}{2} \rfloor\)个字符串. 例如, 当\(n=3\), \(m=3\)和\(a=[010, 111, 001]\)时, 从所有长度为3的二进制字符串中移去\(a_i\), 得到集合\([000, 011, 100, 101, 110]\), 输出中位数100.
解题思路: 数据均为二进制数, 很容易想到使用bitset库. 集合的大小为\(2^m\), 若从中删除元素时间复杂度过高. 考虑使用光标移动替代集合删除元素的过程. 因此需要先求出中间位置\(mid=\lfloor \frac{k-1}{2} \rfloor\), 如果要删除的元素\(\le\)\(mid\), 那么将\(mid\)++, 最后得到的\(mid\)即中间元素十进制值, 用to_string函数转为字符串输出, 并用substr选取最右m位即可.
由于需要对输入元素排序, 所以要用到std::bitset 这样一来便可以用sort进行排序.
/*
* @Author: Hellcat
* @Date: 2020-05-26 11:29:43
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
int T; cin>>T;
while(T--) {
int n, m; cin>>n>>m;
ll a[n+10] = {0};
ll mid = (1ll<<m)-n-1>>1;
for(int i = 1; i <= n; i++) {
string s; cin>>s;
a[i] = bitset<64>(s).to_ullong();
}
sort(a+1, a+1+n);
for(int i = 1; i <= n; i++)
if(a[i] <= mid) mid++;
cout<<bitset<64>(mid).to_string().substr(64-m)<<endl;
}
}