Codeforces Round 943 (Div. 3) 题解 (全)

Update:

G2可以用记忆化过,

口胡下为什么可以过(问了dalao):

首先答案是sqrt(n)种,二分的路径就是sqrt(n)*log(n)

再来一个n,总的复杂度大约是n * sqrt(n) * log(n)

F题属于思维,这个k就按分成两段和三段进行考虑,其他k大于3的都可以转化成二段或者三段。

不要用unordered_map!

为啥

A题: Maximize?

题目大意:

给你一个整数 x, 要求你找出任意一个 y ,y \epsilon [1, x)。使得gcd(x, y) + y最大。

思路一:暴力

数据范围小,直接暴力。

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
void solve() {
	int x; cin >> x;
	int res = 0, id = 1;
	for (int y = 1; y < x; y ++ ) {
		if (__gcd(x, y) + y > res) {
			res = __gcd(x, y) + y;
			id = y;
		}
	}
	cout << id << endl;
}
signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int tt; cin >> tt;
	while (tt -- ) solve();
	return 0;
}

思路二 :动脑子

gcd(x, y) = gcd(x, x - y) \leq x - y

\therefore gcd(x, y) + y \leq x

我们只要令 y = x - 1,那么就可以使得原式子的值为 x。
所以输出 x - 1即可。

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
void solve() {
	int x; cin >> x;
	cout << x - 1 << endl;
}
signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int tt; cin >> tt;
	while (tt -- ) solve();
	return 0;
}

B题: Prefiquence 

题目大意:

给你两个二进制字符串 𝑎 和 𝑏 。二进制字符串是由字符 "0 "和 "1 "组成的字符串。

您的任务是确定最大可能的数字 𝑘 ,使得长度为 𝑘 的字符串 𝑎 的前缀是字符串 𝑏 的子序列。

思路:贪心

如果b中的要取出来跟a的前缀去匹配,那么是不是越早出现越好?
这样就可以让后面空出更多能够跟a去匹配了。

双指针,时间复杂度O(n + m)

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
void solve() {
	int n, m; cin >> n >> m;
    int j = 0, ans = 0;
    string a, b; cin >> a >> b;
    for (int i = 0; i < n; i ++ ) {
        while (j < m && b[j] != a[i]) j += 1;
        if (j == m) break;
        ans += 1, j += 1;
    }
    cout << ans << endl;
}
signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int tt; cin >> tt;
	while (tt -- ) solve();
	return 0;
}

C题: Assembly via Remainders 

题目大意:

给你一个数组 X_{2}, X_{3}, X_{4}...X_{n}。你的任务是找出任意一个数组 a_{1}, a_{2}, a_{3}...a_{n},其中:

  • 1≤a_{i}10^{9} 代表所有 1≤𝑖≤𝑛 。
  • x_{i} = a_{i} % a_{i - 1}

思路:

我们要构造a_{i},如果a_{i - 1}a_{i}大的话,根据模的计算,我们是不是可以就直接放入X_{i}了?

那我们每次构造出的a_{i},都让它等于a_{i - 1} + X_{i},让数组a一直递增,是不是就符合要求了?

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
void solve() {
	int n; cin >> n;
	vector<int> res;
	int last = 600;
	res.push_back(last);
	for (int i = 1; i < n; i ++ ) {
		int x; cin >> x;
		res.push_back(res[i - 1] + x);
	}
	for (auto c : res) cout << c << ' ';
	cout << endl;
}
signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int tt; cin >> tt;
	while (tt -- ) solve();
	return 0;
}

D题: Permutation Game 

题目大意:

见链接。

思路:

如果我们站的位置是最大的,那么我们就不需要移动了对吧,因为可以一直站在上面得到最大的分数。

否则我们就去下一个位置去看看,能不能获得更多的得分。

遍历的话因为是排列,移动是一个环,所以我们最多的遍历次数是 n

用了set避免重复绕环

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
void solve() {
	int n, k, pb, ps; cin >> n >> k >> pb >> ps;
	vector<int> p(n + 1), a(n + 1);
	int maxv = -1;
	for (int i = 1; i <= n; i ++ ) cin >> p[i];
	for (int i = 1; i <= n; i ++ ) cin >> a[i];
	for (int i = 1; i <= n; i ++ ) 
		if (maxv > a[i]) maxv = a[i];
	int score1 = k * a[pb], score2 = k * a[ps];
	int now1 = score1, now2 = score2;
	int cnt = 0;
	unordered_set<int> f1;
	while (a[pb] != maxv && cnt < k) {
		cnt += 1;
		now1 -= (k - cnt) * a[pb];
		f1.insert(pb);
		pb = p[pb];
		if (f1.count(pb)) break;
		now1 += (k - cnt) * a[pb];
		score1 = max(score1, now1);
	}
	cnt = 0;
	f1.clear();
	while (a[ps] != maxv && cnt < k) {
		cnt += 1;
		now2 -= (k - cnt) * a[ps];
		f1.insert(ps);
		ps = p[ps];
		if (f1.count(ps)) break;
		now2 += (k - cnt) * a[ps];
		score2 = max(score2, now2);
	}
	
	if (score1 > score2) cout << "Bodya\n";
	else if (score1 == score2) cout << "Draw\n";
	else cout << "Sasha\n";
}
signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int tt; cin >> tt;
	while (tt -- ) solve();
	return 0;
}

E题: Cells Arrangement 

题目大意:

在 n x n 的方格中找到 n 个点,使得它们之间的曼哈顿距离种类最多。

思路:

我们发现样例中有连起来一块的,还有斜着放着的。

可证:先放(1, 1), 再放(1, 2),最后全部斜着放是能取完所有的距离情况的,这是最大,符合要求。

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
void solve() {
	int n; cin >> n;
	cout << "1 1" << endl;
	cout << "1 2" << endl;
	for (int i = 3; i <= n; i ++ ) {
		cout << i << ' ' << i << endl;
	}
}
signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int tt; cin >> tt;
	while (tt -- ) solve();
	return 0;
}

F题: Equal XOR Segments

代码:

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
const int N = 2e5 + 9;
int a[N], pre[N];
map<int, vector<int>> p;
void solve() {
	int n, q; cin >> n >> q;
	for (int i = 1; i <= n; i ++ ) cin >> a[i];
	for (int i = 1; i <= n; i ++ ) {
		pre[i] = pre[i - 1] ^ a[i];
		p[pre[i]].push_back(i);
	}
	while (q -- ) {
		int l, r; cin >> l >> r;
		if ((pre[r] ^ pre[l - 1]) == 0) {
			cout << "YES\n";
			continue;
		}else {
			auto it = lower_bound(p[pre[r]].begin(), p[pre[r]].end(), l);
			if (it == p[pre[r]].end()) {
				cout << "NO\n";
				continue;
			}	
			int t1 = *it;
			auto _it = upper_bound(p[pre[l - 1]].begin(), p[pre[l - 1]].end(), t1);
			if (_it == p[pre[l - 1]].end()) {
				cout << "NO\n";
				continue;
			}
			int t2 = *_it;
			if (t1 < r && t2 < r) {
				cout << "YES\n";
			}else {
				cout << "NO\n";
			}
		}
	}
	p.clear();
	cout << endl;
}
signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int tt; cin >> tt;
	while (tt -- ) solve();
	return 0;
}

G1:Division + LCP (easy version) 

题目大意:

见链接。

思路:

极其类似砍木头,是二分答案。

每次我们去找字符串 mid 个长度的前缀在整个字符串中的出现次数,

如果大于等于 k,那么 l = mid,否则 r = mid

找的过程(不会Z函数),用了KMP,

时间复杂度O(nlogn)

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
vector<int> nt;
void build(string &s) {
	int n = s.size();
	vector<int> pi(n);
	for (int i = 1; i < n; i ++ ) {
		int j = pi[i - 1];
		while (j > 0 && s[i] != s[j]) j = pi[j - 1];
		if (s[i] == s[j]) j += 1;
		pi[i] = j;
	}
	nt = pi;
}
int KMP(string &t, string &s) {
	build(s);
	int n = t.size(), m = s.size(), j = 0;
	int last = -1e9, ans = 0;
	for (int i = 0; i < n; i ++ ) {
		while (j > 0 && t[i] != s[j]) j = nt[j - 1];
		if (t[i] == s[j]) j += 1;
		if (j == m) {
			int head = i - m + 1;
			if (head >= last + m) {
				ans += 1;
				last = head;
			}
		}
	}
	return ans;
}
void solve() {
	int n, k; cin >> n >> k >> k;
	string s; cin >> s;
	int l = 0, r = n / k + 1;
	while (l + 1 != r) {
		int mid = l + r >> 1;
		string p = s.substr(0, mid);
		if (KMP(s, p) >= k) l = mid;
		else r = mid;
	}
	cout << l << endl;
}
signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int tt; cin >> tt;
	while (tt -- ) solve();
	return 0;
}

G2:Division + LCP (hard version) 

代码:

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
vector<int> nt;
unordered_map<string, int> p;
void build(string &s) {
	int n = s.size();
	vector<int> pi(n);
	for (int i = 1; i < n; i ++ ) {
		int j = pi[i - 1];
		while (j > 0 && s[i] != s[j]) j = pi[j - 1];
		if (s[i] == s[j]) j += 1;
		pi[i] = j;
	}
	nt = pi;
}
int KMP(string &t, string &s) {
	if (p.count(s)) return p[s];
	build(s);
	int n = t.size(), m = s.size(), j = 0;
	int last = -1e9, ans = 0;
	for (int i = 0; i < n; i ++ ) {
		while (j > 0 && t[i] != s[j]) j = nt[j - 1];
		if (t[i] == s[j]) j += 1;
		if (j == m) {
			int head = i - m + 1;
			if (head >= last + m) {
				ans += 1;
				last = head;
			}
		}
	}
	return p[s] = ans;
}
void solve() {
	int n, ll, lr; cin >> n >> ll >> lr;
	string s; cin >> s;
	for (int i = ll; i <= lr; i ++ ) {
		int l = 0, r = n / i + 1;
		while (l + 1 != r) {
			int mid = l + r >> 1;
			string temp = s.substr(0, mid);
			if (KMP(s, temp) >= i) l = mid;
			else r = mid;
		}
		cout << l << ' ';
	}
	p.clear();
	cout << endl;
}
signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int tt; cin >> tt;
	while (tt -- ) solve();
	return 0;
}

  • 27
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
Codeforces Round 894 (Div. 3) 是一个Codeforces举办的比赛,是第894轮的Div. 3级别比赛。它包含了一系列题目,其中包括题目E. Kolya and Movie Theatre。 根据题目描述,E. Kolya and Movie Theatre问题要求我们给定两个字符串,通过三种操作来让字符串a等于字符串b。这三种操作分别为:交换a中相同位置的字符、交换a中对称位置的字符、交换b中对称位置的字符。我们需要先进行一次预处理,替换a中的字符,然后进行上述三种操作,最终得到a等于b的结果。我们需要计算预处理操作的次数。 根据引用的讨论,当且仅当b[i]==b[n-i-1]时,如果a[i]!=a[n-i-1],需要进行一次操作;否则不需要操作。所以我们可以遍历字符串b的前半部分,判断对应位置的字符是否与后半部分对称,并统计需要进行操作的次数。 以上就是Codeforces Round 894 (Div. 3)的简要说明和题目E. Kolya and Movie Theatre的要求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Codeforces Round #498 (Div. 3) (A+B+C+D+E+F)](https://blog.csdn.net/qq_46030630/article/details/108804114)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [Codeforces Round 894 (Div. 3)A~E题解](https://blog.csdn.net/gyeolhada/article/details/132491891)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值