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

Educational Codeforces Round 84 (Rated for Div. 2)

A. Sum of Odd Integers

题意:询问 \(n\) 能否表示为 \(k\) 个不同奇数之和。

分析:首先, \(n\)\(k\) 奇偶性必须一致;其次判一下 \(n\) 是否小于 \(1+3+5+\cdots +(2k-1)=k^2\)

#include <bits/stdc++.h>
#define SIZE 300010
#define rep(i, a, b) for (int i = a; i <= b; ++i)
#define eps 1e-3
#define mp make_pair
#define ll long long
using namespace std;
void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); }
ll t, n, k, a[SIZE];

int main() {
	io(); cin >> t;
	while (t--) {
		cin >> n >> k;
		if (n < k * k || (n - k) % 2) cout << "NO\n";
		else cout << "YES\n";
	}
}

B. Princesses and Princes

题意:题面好长啊不写了。

分析:贪心一下就好了。

#include <bits/stdc++.h>
#define SIZE 300010
#define rep(i, a, b) for (long long i = a; i <= b; ++i)
#define mp make_pair
#define ll long long
using namespace std;
void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); }
vector<int> vec[SIZE];
vector<int> vis;
int n, t;

int main() {
	io(); cin >> t;
	rep(ii, 1, t) {
		cin >> n;
		vis.clear(); vis.resize(n + 1);
		int tp = 0, to = 0;
		rep(i, 1, n) {
			bool f = true;
			int k; cin >> k;
			vec[i].resize(k);
			rep(j, 0, (k - 1)) cin >> vec[i][j];

			for (auto j : vec[i]) {
				if (!vis[j]) {
					vis[j] = true; f = false;
					++tp; break;
				}
			}
			if (f) to = i;
		}
		if (tp == n) cout << "OPTIMAL\n";
		else {
			cout << "IMPROVE\n";
			cout << to << ' ';
			rep(i, 1, n) {
				if (vis[i]) continue;
				cout << i << '\n';
				break;
			}
		}
	}
}

C. Game with Chips

题意\(n\times m\) 的网格图上有 \(k\) 个棋子,坐标为 \((sx_i,sy_i)\) ,每个棋子都有一个对应的必经点坐标 \((fx_i,fy_i)\) 。现在你有最多 \(2nm\) 次移动机会,每次移动能够将棋子整体向上下左右四个方向中的一个移动一个单位(如果棋子到达边界将不再移动,棋子可以重叠),给出一种能够让每个棋子到达必经点的方案。

分析:我们直接将所有棋子都移动到左上角,然后 \(S\) 形遍历棋盘。

#include <bits/stdc++.h>
#define SIZE 210
#define rep(i, a, b) for (long long i = a; i <= b; ++i)
#define mp make_pair
#define ll long long
using namespace std;
void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); }
int n, m, k;
string s;
struct Point {
	int x, y;
}p[SIZE];
 
int main() {
	io(); cin >> n >> m >> k;
	rep(i, 1, (k + k)) cin >> p[i].x >> p[i].y >> p[i].x >> p[i].y;
	rep(i, 1, (n - 1)) s.push_back('U');
	rep(i, 1, (m - 1)) s.push_back('L');
	int f = 1;
	rep(i, 1, n) {
		rep(j, 1, (m - 1)) {
			if (f) s.push_back('R');
			else s.push_back('L');
		}
		s.push_back('D');
		f ^= 1;
	}
	cout << s.length() << '\n' << s;
}

D. Infinite Path

题意:给定一个 \(1,2,\cdots,n\) 的排列 \(p_i\) ,位置 \(i\) 染色为 \(c_i\) 。定义一条无穷路径指的是:存在这样一个无穷序列 \(i,p[i],p[p[i]],...p^{(n)}[p[i]]\) ,该序列对应的每个位置颜色相同;再定义 \(k\) 阶迭代指的是:对每个位置 \(i\) ,进行 \(k\) 次迭代后得到的序列(即 \(i\) 迭代为 \(p[i]\) ,再迭代为 \(p[p[i]]\cdots\) )。询问至少进行几阶迭代后,至少存在一条无穷路径。

分析:首先,因为 \(p\) 是一个排列,因此如果以 \((i,p[i])\) 建边,将得到一个由数个有向环构成的图,因此本题的关键在于一个大环在什么情况下会分离成小环。假设其中一个环有 \(m\) 个点,从环中的某个起点 \(s\) 出发,进行 \(k\) 次迭代后,其所在环的点集变为 \((s+ck)\% m(c\in Z)\) (每次迭代相当于某个点 \(i\) 移动至 \(p[i]\) )。同时注意到,如果 \(k\) 不是 \(m\) 的因子,那么在同余意义下,环不会分裂;若 \(k\)\(m\) 的因子且 \(pk=m\) 那么环将分裂成 \(k\) 个由 \(p\) 个点构成的小环。因此,我们对于 \(k\) 的每个因子拆环判断是否同色即可。

由于题目中给出的 \(k\leq 2e5\) ,因此一个数的最大因子数不超过 \(160\) ,因此我们可以 \(O(160n)\) 模拟这一过程。

#include <bits/stdc++.h>
#define SIZE 300010
#define rep(i, a, b) for (int i = a; i <= b; ++i)
#define eps 1e-3
#define mp make_pair
#define ll long long
using namespace std;
void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); }
int t, n, ans;
int p[SIZE], c[SIZE];
 
int main() {
	io(); cin >> t;
	rep(ii, 1, t) {
		cin >> n; ans = n;
		rep(i, 0, (n - 1)) cin >> p[i], --p[i];
		rep(i, 0, (n - 1)) cin >> c[i];
		rep(i, 0, (n - 1)) {
			if (p[i] == -1) continue;
			vector<int> vec;
			for (int j = i; p[j] != -1;) {
				vec.emplace_back(c[j]);
				int to = p[j];
				p[j] = -1;
				j = to;
			}
			rep(j, 1, vec.size()) {
				if (vec.size() % j) continue;
				rep(s, 0, (j - 1)) {
					bool f = true;
					for (int k = s; k < vec.size(); k += j) {
						if (vec[k] != vec[s]) {
							f = false;
							break;
						}
					}
					if (f) {
						ans = min(ans, j);
						break;
					}
				}
			}
		}
		cout << ans << '\n';
	}
}

E. Count The Blocks

题意:统计 \(0,1,2,\cdots,10^{n}-1\) 所有数字中不同长度的连续区间数。例如 \(0111223\) 中有 \(2\) 段长度为 \(1\) 的区间, \(1\) 段长度为 \(2\) 的区间, \(1\) 段长度为 \(3\) 的区间。(如果数字不足 \(n\) 位需要补充前导零)

分析:找规律!\(a[1]=10,a[2]=180,a[3]=2610,a[i]=20a[i-1]-100a[i-2](i>3)\)

#include <bits/stdc++.h>
#define SIZE 300010
#define rep(i, a, b) for (long long i = a; i <= b; ++i)
#define int long long
#define ll long long
using namespace std;
void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); }
const int P = 998244353;
int n, a[SIZE];

signed main() {
	io(); n = 300000ll;
	a[0] = 10ll; a[1] = 180ll; a[2] = 2610ll;
	rep(i, 3, n) a[i] = ((20ll * a[i - 1] - 100ll * a[i - 2]) % P + P) % P;
	cin >> n;
	for (int i = n; i; --i) cout << a[i - 1] % P << ' ';
}
posted @ 2020-03-24 10:50  st1vdy  阅读(387)  评论(0编辑  收藏  举报