题解 Educational Codeforces Round 84 (Rated for Div. 2) A

侃侃:

之后做的题,发现几天不做题,脑子都不够用了,基本的模拟都不会写了,可能本来就菜吧。
做了做前三道基本的题,发现也不简单呀!

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
");
			printf("%d %d
",pos1,pos2);
		} else {
			printf("OPTIMAL
");
		}
	}
	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
",road.size());
	cout << road << endl;
	return 0;
}

后记:

一般来说 CF 的前几道题都是比较基础的,突然发现自己学的很多算法都没有用上,
难道是老了,思维跟不上?那一定是自己太菜了。
读题真的是十分重要的,很多细节都会通过题意表达出来,吃一堑,长一智,以后做题的
时候先将所有的细节标注下来,尤其是黑体强调的东西。
还有,乘法一定要记得 long long .

加油!自信一点。
原文地址:https://www.cnblogs.com/prjruckyone/p/12560484.html