返回顶部

AtCoder Beginner Contest 234题解

AtCoder Beginner Contest 234

比赛的时候过了E,赛后三分钟过了F QAQ

A - Weird Function

题目描述:已知函数\(f(x) = x^2 +2x + 3\),给你一个整数\(t\),求\(f(f(f(t) + t) + f(f(t)))\).

思路:根据题意模拟即可。

时间复杂度:\(O(1)\)

参考代码:

void solve() {
	auto f = [](int x)->int {
		return x * x + 2 * x + 3;
	};
	int x(0);
	cin >> x;
	int res = f(f(f(x) + x) + f(f(x)));
	cout << res << '\n';
	return ;
}

B - Longest Segment

题目描述:给你\(n\)个二维平面上的点,求任意两点之间的最大距离。

思路:考虑到\(1\leq n \leq 100\),所以直接\(O(n^2)\)暴力即可。

时间复杂度:\(O(n^2)\)

参考代码:

struct Point {
	int x, y;
	Point(int _x = 0 , int _y = 0):x(_x) , y(_y){}
};
void solve() {
	int n;
	cin >> n;
	vector<Point> points(n);
	for (int i = 0; i < n; ++i) cin >> points[i].x >> points[i].y;
	double res = 0;
	auto cal = [&](const Point& a, const Point& b)->double {
		int dx = (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
		return sqrt(dx * 1.0);
	};
	for (int i = 0; i < n; ++i)
		for (int j = i + 1; j < n; ++j) 
			res = max(res, cal(points[i], points[j]));
	printf("%.10lf\n", res);
	return ;
}

C - Happy New Year!

题目描述:给你一个整数\(K(1 \leq K \leq 10^{18})\),让你求第\(k\)小的只含有0 , 2的字符串。

思路:把\(K\)转化成二进制,然后将二进制中的1换成2即可。

时间复杂度:\(O(logK)\)

参考代码:

void solve() {
	long long k = 0;
	cin >> k;
	string res;
	for (int i = 0; i <= 62; ++i) {
		if ((k >> i) & 1) res += '2';
		else res += '0';
	}
	while (res.size() > 1 && res.back() == '0') res.pop_back();
	reverse(res.begin(), res.end());
	cout << res << '\n';
	return ;
}

D - Prefix K-th Max

题目描述:给你一个长度为\(N\)的排列和一个整数\(K\),让你输出前缀长度分别为$K + 1 , K + 2 , ... ,N \(的前缀的第\)K$大数。

思路:直接维护一个大小为\(K\)的小根堆即可。

时间复杂度:\(O(nlogn)\)

参考代码:

void solve() {
	int n = 0, k = 0;
	cin >> n >> k;
	vector<int>a(n + 1, 0);
	for (int i = 1; i <= n; ++i) cin >> a[i];
	priority_queue<int, vector<int>, greater<int>>heap;
	for (int i = 1; i < k; ++i) heap.push(a[i]);
	for (int i = k; i <= n; ++i) {
		if (heap.size() < k) heap.push(a[i]);
		else if (heap.top() < a[i]) {
			heap.pop();
			heap.push(a[i]);
		}
		cout << heap.top() << '\n';
	}
	return ;
}

E - Arithmetic Number

题目描述:给你一个整数\(x\;(1 \leq x \leq 10^{17})\),让你求不小于\(x\)且最小的整数\(S\)满足下列条件:

假设\(S\)\(n\)位且\(S_i\)表示\(S\)的第\(i\)个数字,则\(S_2 - S_1 = S_3 - S_2 = .. = S_n - S_{n - 1}\)

思路:考虑到\(x\)最多只有\(17\)位,考虑暴力枚举第一个数字和公差构造一个长度与\(x\)相同的数字并判断与\(x\)的大小关系并更新答案即可,答案最大为\(n + 1\)\(1\)

时间复杂度:\(O(9\times 16 \times n)\)

参考代码:

void chkmin(string& s, string& t) {
	if (s.size() > t.size()) s = t;
	else s = min(s, t);
	return;
}
void solve() {
	string s;
	cin >> s;
	string res;
	int n = s.size();
	for (int i = 1; i <= n + 1; ++i) res += '1';
	for (int i = 1; i <= 9; ++i) {
		for (int d = -8; d <= 8; ++d) {
			string t;
			t += (char)('0' + i);
			int last = i;
			for (int j = 2; j <= n; ++j) {
				if (d + last > 9 || d + last < 0) break;
				last = d + last;
				t += (char)('0' + last);
			}
			if (t.size() < n) continue;
			if (t < s) continue;
			chkmin(res, t);
		}
	}
	cout << res << '\n';
	return ;
}

F - Reordering

题目描述:给你一个长度为\(n\)的只含有小写字母的字符串\(s\),对于它的所有子串的排列数的总和是多少。

数据范围:\(1 \leq n \leq 5000\)

思路:考虑先按照字符进行统计,则最多有\(26\)种字符,定义状态\(f_{i , j}\)表示以第\(i\)个字符结尾的长度为\(j\)的方案数。对于相同的字符,我们直接枚举每次取多少个与前面不相同的字符对答案进行贡献。假设我们枚举到第\(k\)种字符,且前面\(k - 1\)种字符共有\(len\)个,那么当前枚举第\(k\)种字符的第\(r\)个时,状态转移为:

\[f[r + len][j + r] = \begin{cases} 1 & j = 0\\ \frac{f[len , j] * \prod\limits_{p = 1}^{j + r} p}{\prod\limits_{p = 1}^{r}p\prod\limits_{q = 1}^{j}q} & j \neq 0 \end{cases}\\ f[r + len][j] += f[r + len - 1][j] \]

答案为\(\sum\limits_{i = 1}^{n} f_{n , i}\)

对于\(j \neq 0\)时的转移做如下解释:考虑当前有一个长度为\(len\)的字符串且没有字符与当前枚举的字符相同,然后要插入\(r\)个当前枚举的字符,根据组合数学可知方案数为\(\frac{(len + r)!}{(len)!r!}\) ,该长度为\(len\)的字符串有\(f[len , j]\)个,故对答案的贡献就是将二者相乘。

时间复杂度:阶乘可以\(O(n)\)预处理,然后求逆元需要\(O(log\;mod)\),枚举不同字符的复杂度是\(O(n^2)\)的,故总的复杂度为:\(O(n^2log\;mod + n)\)

参考代码:

const int mod = 998244353;
int quickPow(int a, int p) {
	int res = 1;
	while (p) {
		if (p & 1) res = 1ll * res * a % mod;
		a = 1ll * a * a % mod;
		p >>= 1;
	}
	return res;
}
void solve() {
	string s;
	cin >> s;
	vector<int>cnt(27, 0);
	for (auto c : s) cnt[c - 'a' + 1]++;
	int n = s.size();
	vector<int>p(n + 10, 0);
	p[0] = 1;
	for (int i = 1; i <= n + 5; ++i) p[i] = 1ll * p[i - 1] * i % mod;
	vector<vector<int>>f(n + 1, vector<int>(n + 1 , 0));
	//表示以第i个字符结尾 长度为j的方案数
	int len = 0;
	for (int k = 1; k <= 26; ++k) {
		if (cnt[k] == 0) continue;
		int newlen = len;
		for (int r =  1; r <= cnt[k]; ++r) {
			int i = r + len;
			for (int j = 0; j <= len; ++j) {
				long long dx = f[len][j];
				f[i][j + r] += dx * p[j + r] % mod 
					* quickPow(1ll * p[r] * p[j] % mod, mod - 2) % mod;
				if (j == 0) f[i][j + r] = 1;
			}
			for (int j = 1; j <= r + len; ++j) f[r + len][j] = (f[r + len][j] + f[r + len - 1][j]) % mod;
		}
		len += cnt[k];
	}
	int res = 0;
	for (int i = 1; i <= n; ++i) res = (res + f[n][i]) % mod;
	cout << res << '\n';
	return ;
}
posted @ 2022-01-08 22:27  cherish-lgb  阅读(309)  评论(0编辑  收藏  举报