Codeforces Round #739 (Div. 3)

本文详细解析了Codeforces Round #739 (Div. 3)中的五道算法题目,涵盖数论、几何、矩阵填充、数字操作和字符串处理等核心算法知识点。通过暴力枚举、数学推理和模拟等方法,阐述了解题思路和优化技巧,旨在提升参赛者的算法思维和编程能力。
摘要由CSDN通过智能技术生成

Codeforces Round #739 (Div. 3)

A题

题意:找出第K个不能被3整除且末尾不是3的数
思路:暴力打表

#include<bits/stdc++.h>
#include <unordered_map>
using namespace std;
template<class...Args>
void debug(Args... args) {//Parameter pack
	auto tmp = { (cout << args << ' ', 0)... };
	cout << "\n";
}
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>pll;
typedef pair<int, int>pii;
const ll N = 5e5 + 5;
const ll INF = 0x7fffffff;
const ll MOD = 1e9 + 7;

int main() {
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	
	vector<int>v;
	for (int i = 1; i < 3000; i++) {
		if (i % 3 != 0) {
			if (i % 10 != 3)v.push_back(i);
		}
	}
	/*cout << v.size() << "\n";
	for (auto i : v)cout << i << " ";*/

	int t;
	cin >> t;
	while (t--) {
		int k;
		cin >> k;
		cout << v[k-1] << "\n";
	}
	

	return 0;
}

B题

题意:若干个数按顺时针排列成圆,且关于圆心一一对称,告诉你其中对称的一组数 a 、 b ,求与 c 对称的数
思路:计算出总人数 n u m = 2 ∗ a b s ( a − b ) num=2*abs(a-b) num=2abs(ab),再进行判断即可。

#include<bits/stdc++.h>
#include <unordered_map>
using namespace std;
template<class...Args>
void debug(Args... args) {//Parameter pack
	auto tmp = { (cout << args << ' ', 0)... };
	cout << "\n";
}
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>pll;
typedef pair<int, int>pii;
const ll N = 5e5 + 5;
const ll INF = 0x7fffffff;
const ll MOD = 1e9 + 7;

int main() {
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	
	int t;
	cin >> t;
	while (t--) {
		int a, b, c;
		cin >> a >> b >> c;
		int t = abs(a - b);
		int num = 2 * t;
		if (a > num || b > num || c > num)cout << -1 << "\n";
		else {
			if (c - t > 0) cout << c - t << "\n";
			else if (c + t <= num)cout << c + t << "\n";
			else cout << -1 << "\n";
		}
	}
	

	return 0;
}

C题

题意:给你个矩阵,这个矩阵以某种方式填充数,问你第 k 个数的坐标是多少?
思路:注意到每列第一个为这层最大的数,根据给定步数找到最大的起始位置然后计算步数差手动回退下即可。

#include<bits/stdc++.h>
#include <unordered_map>
using namespace std;
template<class...Args>
void debug(Args... args) {//Parameter pack
	auto tmp = { (cout << args << ' ', 0)... };
	cout << "\n";
}
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>pll;
typedef pair<int, int>pii;
const ll N = 5e5 + 5;
const ll INF = 0x7fffffff;
const ll MOD = 1e9 + 7;

int main() {
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	
	vector<ll> x;
	x.push_back(1);
	ll d = 3;
	ll sum = 1;
	while (1) {
		x.push_back(x.back() + d);
		d += 2;
		sum = sum + d;
		if (sum > MOD)break;
	}
	x.push_back(x.back() + d);
	//for (auto i : x)cout << i << "\n";
	int t;
	cin >> t;
	while (t--) {
		int n;
		cin >> n;
		int pos = lower_bound(x.begin(), x.end(), n) - x.begin();
		//cout << pos << "\t"<<x[pos]<<"\n";
		int d = x[pos] - n;
		int x, y;
		if (d <= pos)x = 1 + d, y = pos + 1;
		else x = 1 + pos, y = pos - (d - (1 + pos));
		cout << y << " " << x << "\n";
		//cout << pos << " "<<x[pos]<<"\n";
	}

	return 0;
}

D题

题意:

给定数字num,给定两种操作

  • 1.从右边加入一个数
  • 2.删除任意一个数

问最少多少次操作后所给数字能变成 2 n 2^n 2n的形式

思路:

注意到因为是从右边加入一个数字所以之前数字能在一个2的某次幂满足要求越多越好

我们将 [ 2 0 , 2 64 ] [2^0,2^{64}] [20,264]所有的数打表打出来,然后一个一个计算这个数变成2的某次幂的所需步骤取最小的即可。

匹配的过程类似于KMP的过程

#include<bits/stdc++.h>
#include <unordered_map>
using namespace std;
template<class...Args>
void debug(Args... args) {//Parameter pack
	auto tmp = { (cout << args << ' ', 0)... };
	cout << "\n";
}
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>pll;
typedef pair<int, int>pii;
const ll N = 5e5 + 5;
const ll INF = 0x7fffffff;
const ll MOD = 1e9 + 7;

vector<ll>v;
vector<ll>num[64];//2的64
void init() {
	ll t = 1;
	for (ll i = 1; i < 64; i ++) v.push_back(t),t*=2;
	for (int i = 0; i < v.size(); i++) {
		ll t = v[i];
		while (t)num[i].push_back(t % 10), t /= 10;
		reverse(num[i].begin(), num[i].end());
	}
}
int solve(int n,int pos) {//计算从n变为num[pos]所需步数
	vector<ll>t;
	while (n)t.push_back(n % 10), n /= 10;
	reverse(t.begin(), t.end());
	int cnt = 0, i = 0, j = 0;
	while(j < t.size()&& i < num[pos].size()) {
		if (num[pos][i] == t[j])i++, j++;
		else j++,cnt++;
	}
	cnt = cnt + (num[pos].size() - i) + (t.size() - j);
	return cnt;
}
int main() {
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	
	init();
	int t;
	cin >> t;
	while (t--) {
		int n;
		cin >> n;
		int ans = INF;
		for (int i = 0; i < v.size(); i++) ans = min(ans,solve(n, i));
		cout << ans << "\n";
	}

	return 0;
}

E题

题意:假设有这样一个字符串 s 和一个空字符串 t , 字符串 s 可以执行下列操作直至其为空:

  • 先令 t=t+s
  • 再移除 s 中所有的某字母

现在给你一个 t 串,问你能否倒推出 s 串和字母的删除顺序。

思路:
首先对于给定的字符串从后往前出现过的记录那么第一次出现的就都属于删除字母,具体来说删除字母的顺序应该是顺序统计出来的删除字母的逆序。

记录下字母 a 的出现次数 cnta ,即 a 在原串中的出现次数为 numa=cnta/i ,所有字母的 num 之和即为原串 s 的长度,那 s 也就可以随之确定了

确定了s和删除字母的顺序然后按题意模拟一遍判断就行。

#include<bits/stdc++.h>
#include <unordered_map>
using namespace std;
template<class...Args>
void debug(Args... args) {//Parameter pack
	auto tmp = { (cout << args << ' ', 0)... };
	cout << "\n";
}
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>pll;
typedef pair<int, int>pii;
const ll N = 1e5 + 5;
const ll INF = 0x7fffffff;
const ll MOD = 1e9 + 7;
string solve(string t,string s) {//模拟题目过程
	string ans = t;
	for (int i = 0; i < s.length(); i++) {
		string temp;
		for (int j = 0; j < t.length(); j++) if (t[j] != s[i])temp.push_back(t[j]);
		t = temp;
		ans += t;
	}
	return ans;
}
int main() {
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);

	int t;
	cin >> t;
	while (t--) {
		string temp, s;
		cin >> temp;
		map<char, int>m;
		for (int i = temp.length() - 1; i >= 0; i--) {
			if (!m[temp[i]])s.push_back(temp[i]);
			m[temp[i]]++;
		}
		reverse(s.begin(), s.end());

		int len = 0;
		for (int i = 0; i < s.size(); i++)len += m[s[i]] / (i + 1);
		string tt = temp.substr(0, len);

		if (temp == solve(tt,s))cout << tt << " " << s << "\n";
		else cout << -1 << "\n";
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值