题解 Educational Codeforces Round 84 (Rated for Div. 2) A - C
侃侃:
之后做的题,发现几天不做题,脑子都不够用了,基本的模拟都不会写了,可能本来就菜吧。
做了做前三道基本的题,发现也不简单呀!
A. Sum of Odd Integers
题目大意:
给一个整数,再给一个 k ,问这个数是否可以由几个 不同的 奇数和 得到?
考察点:
奇数偶数的性质,以及你的推导能力。
坑点:
1、两个数相乘可能会 爆 int,所以需要用 long long
2、需要特判 k * k > n,首先一定要有 k 个奇数,如果这几个最小的奇数
都比 n 大了,那么必然是无法得到的。
Code:
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int main(void) {
long long t,n,k;
cin >> t;
while(t --) {
cin >> n >> k;
// k 个不同的奇数能表示的最小数 是 k * k
if(k > n || n < k * k) cout << "NO" << endl;
// 分奇数偶数情况进行讨论
else if(n & 1) {
if(k & 1) cout << "YES" << endl;
else cout << "NO" << endl;
} else {
if(k & 1) cout << "NO" << endl;
else cout << "YES" << endl;
}
}
return 0;
}
B. Princesses and Princes
题目大意:
公主和王子进行匹配,每个公主可以有一个王子的候选名单,王子名单的价值是按照价值从大
到小已经排好序的,当然,每个公主只能选择一个王子,最后如果所有公主和王子都可以成功
匹配,那么就不用增加了,否则找到一个未配对的公主,然后再寻找一个未配对的王子,两个进
行配对。
侃侃:
刚开始一看图以为是二分图匹配,但更扯淡的是这道题的介绍也太长了,英文水平实在有限,
不得不使用辅助工具、
还有就是一些细节需要注意,尤其是 0 的情况,例如第二个样例。
Code:
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
int vis[maxn],cnt[maxn];
int t,n,op,g;
int main(void) {
scanf("%d",&t);
while(t --) {
scanf("%d",&n);
memset(vis,0,sizeof(vis));
bool flag = false;
int pos1 = -1,pos2;
for(int i = 1; i <= n; i ++) {
scanf("%d",&op);
// 为什么不在这里进行取最小值进行判断,太过麻烦,而且有可能 op = 0
for(int k = 1; k <= op; k ++) {
scanf("%d",&cnt[k]);
}
int v = 0;
// 选择一个合适的王子进行配对(没有被其他人选过)
for(int k = 1; k <= op; k ++) {
if(vis[cnt[k]] == 0) {
vis[cnt[k]] = 1;
v = 1;
break;
}
}
// 如果已经找到一个值,那么之后就不需要再找了
if(pos1 != -1) continue;
if(v == 0) {
pos1 = i;
}
}
for(int i = 1; i <= n; i ++) {
if(vis[i]) continue;
pos2 = i;
break;
}
if(pos1 != -1) {
printf("IMPROVE\n");
printf("%d %d\n",pos1,pos2);
} else {
printf("OPTIMAL\n");
}
}
return 0;
}
C. Game with Chips
题目大意:
有一个 n * m 的矩阵,之后给一些起点和终点,问最后每个起点和终点重合需要
走多少步,打印其路径。
侃侃:
题目说我们最多不能超过 2 * n * m 步,那么我们首先可以得到一个信息就是
我们走完 整个矩阵只需要 n * m 步。
这道题比较良心的是并没有要求我们走的是最小步数,而且题目中还用加粗强调了
多个起点可以在同一个地方(我一定是瞎了,不,我可能暂时还没学会根据题目给的
信息去做推导),我们可以把所有的起点都放到同一个角落,然后从起点走完整个
矩阵就可以了(这方法真的是巧妙,我怎么就想不到呢?)
细节:
第一次将所有点都归置到一个角落:
n + m - 2
第二次走完矩阵:
n *m - 1
n + m + n * m - 1 < 2 * n * m
必然满足题目的要求。
Code:
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 205;
int a[maxn][maxn],vis[maxn][maxn];
int dir[][2] = {{1,0},{-1,0},{0,1},{0,-1}};
string road;
int n,m,k;
int x,y,u,v;
void DFS(int sx,int sy) {
vis[sx][sy] = 1;
for(int i = 0; i < 4; i ++) {
int x = sx + dir[i][0];
int y = sy + dir[i][1];
if(x < 1 || y < 1 || x > n || y > m) continue;
if(vis[x][y]) continue;
vis[x][y] = 1;
if(dir[i][0] == 1 && dir[i][1] == 0) {
road += 'D';
DFS(x,y);
} else if(dir[i][0] == -1 && dir[i][1] == 0) {
road += 'U';
DFS(x,y);
} else if(dir[i][0] == 0 && dir[i][1] == 1) {
road += 'R';
DFS(x,y);
} else if(dir[i][0] == 0 && dir[i][1] == -1) {
road += 'L';
DFS(x,y);
}
}
return ;
}
int main(void) {
scanf("%d%d%d",&n,&m,&k);
for(int i = 1; i <= k ; i ++) {
scanf("%d%d",&x,&y);
}
for(int j = 1; j <= k ; j ++) {
scanf("%d%d",&u,&v);
}
for(int i = 1; i < n; i ++) {
road += 'U';
}
for(int j = 1; j < m; j ++) {
road += 'L';
}
DFS(1,1);
printf("%d\n",road.size());
cout << road << endl;
return 0;
}
后记:
一般来说 CF 的前几道题都是比较基础的,突然发现自己学的很多算法都没有用上,
难道是老了,思维跟不上?那一定是自己太菜了。
读题真的是十分重要的,很多细节都会通过题意表达出来,吃一堑,长一智,以后做题的
时候先将所有的细节标注下来,尤其是黑体强调的东西。
还有,乘法一定要记得 long long .
加油!自信一点。
如果说年轻人未来是一场盛宴的话,那么我首先要有赴宴的资格。