返回顶部

AtCoder Beginner Contest 234题解

作者:@cherish.
课程学习内容为作者从学校的PPT处摘抄,仅供自己学习参考,若需转载请注明出处:https://www.cnblogs.com/cherish-/p/15779852.html


AtCoder Beginner Contest 234

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

A - Weird Function

题目描述:已知函数f(x)=x2+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个二维平面上的点,求任意两点之间的最大距离。

思路:考虑到1n100,所以直接O(n2)暴力即可。

时间复杂度:O(n2)

参考代码:

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(1K1018),让你求第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(1x1017),让你求不小于x且最小的整数S满足下列条件:

假设Sn位且Si表示S的第i个数字,则S2S1=S3S2=..=SnSn1

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

时间复杂度:O(9×16×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,对于它的所有子串的排列数的总和是多少。

数据范围:1n5000

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

f[r+len][j+r]={1j=0f[len,j]p=1j+rpp=1rpq=1jqj0f[r+len][j]+=f[r+len1][j]

答案为i=1nfn,i

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

时间复杂度:阶乘可以O(n)预处理,然后求逆元需要O(logmod),枚举不同字符的复杂度是O(n2)的,故总的复杂度为:O(n2logmod+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 @   cherish-lgb  阅读(326)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· Apache Tomcat RCE漏洞复现(CVE-2025-24813)
点击右上角即可分享
微信分享提示