Codeforces Round 945 (Div. 2) 题解分享

发布于:2024-05-20 ⋅ 阅读:(56) ⋅ 点赞:(0)

前排提醒:

就只有A~D题。

题目大意就不放啦,可以点链接去看题目。

思路我就写我写时候的思路,希望能对你有帮助qwq

A题:Chess For Three

Q:什么情况是不可能出现的?

A:总得分为奇数的情况是不可能出现的,因为要得分,只能一个人加两分,或者两个人每个人加一分,不可能出现奇数的情况。

Q:怎么使得平局次数最多呢?

A:当然,如果得分全都是由平局得来的话次数肯定最多。

题目给了一个信息,a是单调不减的。

我们有三种搭配方式, a1 - a2  a1 - a3  a2 - a3

所以去进行搭配的只是a1和a2,

a3特别大的时候,答案是a1+a2

这个特别大我们可以推出来是 a3 > a1 + a2

这就成为了我们分类讨论的依据

而 a3 <= a1 + a2的时候,

a3 - a1 <= a2

可以考虑它们的奇偶性,a3 - a1和 a2 差 2的倍数 (0, 1, 2 ...)

也就是说 a1 可以使得 a2和a3配成相等

如 3 4 5

ans = 3 + (0, 3,3) = 3 + 3 = 6

#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
#define int long long
#define endl '\n'
//#define LOCAL
 
inline void solve() {
    int a[3], sum = 0;
    for (int i = 0; i < 3; i ++ ) cin >> a[i], sum += a[i];
    if (sum & 1) return cout << -1 << endl, void();
    if (a[2] - a[1] > a[0]) {
        cout << a[0] + a[1] << endl;
    }else {
        cout << sum / 2 << endl;
    }
}
 
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
#ifdef LOCAL
    freopen("in.in", "r", stdin);
    freopen("out.out", "w", stdout);
#endif
    int tt; tt = 1;
    cin >> tt;
    while (tt -- ) solve();
    return 0;
}

 

B题:Cat, Fox and the Lonely Array

Q:怎么去找最小的K啊?

A:题目要求我们去找最小的K,那么一定可以有更大的K满足题意的对吧。

Q:有道理,所以小于最小的K不满足题意,大于最小的K满足题意?

A:是这样的,这样你就想出来了二分这种解法了对吧?我来给你更严谨点

左边是k = 5的情况,右边是k = 6的情况

x x x x x                x x x x x x

   x x x x x                x x x x x x

右边上面那段是由左边上下两端或起来的,右边下面是由另外两段或起来的。

而左边每段或起来的值相等,就推出来了右边每段或起来的值相等。

Q:嗷,我知道了,那怎么求出来一段区间的或值呢?

A:这题可以窗口,也可以暴力上ST表,ST表更清楚些

#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
#define int long long
#define endl '\n'
//#define LOCAL
const int N = 1e5 + 9;
int a[N], st[N][20], lg2[N];
inline void build(int n) {
    for (int i = 1; i <= n; i ++ ) st[i][0] = a[i];
    for (int j = 1; (1 << j) <= n; j ++ ) {
        for (int i = 1; i + (1 << (j - 1)) <= n; i ++ ) {
            st[i][j] = st[i][j - 1] | st[i + (1 << (j - 1))][j - 1];
        }
    }
}
inline int query(int l, int r) {
    int s = lg2[r - l + 1];
    return st[l][s] | st[r - (1 << s) + 1][s];
}
inline void solve() {
    int n; cin >> n;
    for (int i = 1; i <= n; i ++ ) cin >> a[i];
    build(n);
    int l = 0, r = n + 1;
    while (l + 1 != r) {
        int mid = (l + r) >> 1;
        int cur = query(1, mid);
        bool ok = true;
        for (int i = 2; i + mid - 1 <= n; i ++ ) {
            if (query(i, i + mid - 1) != cur) {
                ok = false;
                break;
            }
        }
        if (ok) r = mid;
        else l = mid;
    }
    cout << r << endl;
}
 
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
#ifdef LOCAL
    freopen("in.in", "r", stdin);
    freopen("out.out", "w", stdout);
#endif
    for (int i = 2; i < N; i ++ ) lg2[i] = lg2[i >> 1] + 1;
    int tt; tt = 1;
    cin >> tt;
    while (tt -- ) solve();
    return 0;
}

 

C题:Cat, Fox and Double Maximum

Q:题目我看懂了,该怎么构造呢?

A:n是偶数对吧?

Q:是的。

A:那最理想构造出几个?

Q:(n - 2) / 2个,中间隔一个就有一个局部最大。

A:就这么构造

Q:你的意思是,要让一些成为局部最大的点的点配上最大,另一些配上最小?

1 2 3 4 5 6

我们让2,4成为局部最大,就配6 5

其他配4 3 2 1,所以是4 6 3 5 2 1?

也可以是3,5成为局部最大,配6 5

其他配4 3 2 1,成4 3 6 2 5 1?

两种情况一定能出一个(n - 2) / 2?这么做的理由是什么?

A:我猜对了,就花了8min。

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
typedef pair<int, int> PII;
//#define LOCAL

inline void solve() {
	int n; cin >> n;
	vector<int> a(n + 1);
	for (int i = 1; i <= n; i ++ ) cin >> a[i];
	vector<PII> b, c;
	for (int i = 1; i <= n; i ++ ) {
		if (i % 2 == 0 && i != n) {
			b.push_back({a[i], i});
		}else {
			c.push_back({a[i], i});
		}
	}
	sort(b.begin(), b.end());
	int cur = n;
	vector<int> res(n + 1);
	for (int i = 0; i < b.size(); i ++ ) {
		res[b[i].second] = cur --;
	}
	sort(c.begin(), c.end());
	for (int i = 0; i < c.size(); i ++ ) {
		res[c[i].second] = cur --;
	}
	vector<int> temp(n + 1);
	for (int i = 1; i <= n; i ++ ) {
		temp[i] = res[i] + a[i];
	}
	int cnt = 0;
	for (int i = 2; i < n; i ++ ) {
		if (temp[i] > temp[i - 1] && temp[i] > temp[i + 1]) cnt += 1;
	}
	if (cnt == (n - 2) / 2) {
		for (int i = 1; i <= n; i ++ ) cout << res[i] << ' ';
		cout << endl;
		return;
	}
	b.clear(), c.clear();
	for (int i = 1; i <= n; i ++ ) {
		if (i & 1 && i != 1) {
			b.push_back({a[i], i});
		}else {
			c.push_back({a[i], i});
		}
	}
	sort(b.begin(), b.end());
	cur = n;
	res.clear();
	for (int i = 0; i < b.size(); i ++ ) {
		res[b[i].second] = cur --;
	}
	sort(c.begin(), c.end());
	for (int i = 0; i < c.size(); i ++ ) {
		res[c[i].second] = cur --;
	}
	for (int i = 1; i <= n; i ++ ) cout << res[i] << ' ';
	cout << endl;
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
#ifdef LOCAL
    freopen("in.in", "r", stdin);
    freopen("out.out", "w", stdout);
#endif
    int tt; tt = 1;
    cin >> tt;
    while (tt -- ) solve();
    return 0;
}

D题: Cat, Fox and Maximum Array Split

Q:如果已经知道a数组了,这个构造也是很麻烦啊。

A:所以是交互题

Q:该怎么做呢?

A:题目给的最大次数是2 * n,所以它是想让你去遍历n,也就是a数组。我们先去考虑这个数组中的最大值,每次可以ask(1,i * n),当返回值是n的时候,i就是数组中的最大值,这样的操作次数最大是n

接着我们可以考虑最大值所在区间的长度,长度最大是 n / k (下取整)

Q:为什么长度最大是 n / k ?

A:你这样想,按题目意思,如果区间中最大值越大,那么我们要配成一样的话是不是长度要越小?

Q:是的,没毛病

A:如果就只有一段有最大值,那么其他段的长度都要比其长度大一点,这样就使得其小于 n / k了,但是全有最大值的话,就可以是 n / k了。

#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int, int> PII;
//#define LOCAL
int ask(int l, int w) {
	cout << "? " << l << " " << w << endl;
	int r; cin >> r;
	return r;
}
inline void solve() {
	int n, k; cin >> n >> k;
	int maxv;
	for (int i = 1; i <= n; i ++ ) {
		int r = ask(1, n * i);
		if (r == n) {
			maxv = i;
			break;
		}
	}
	for (int i = n / k; i >= 1; i -- ) {
		int head = 1, cnt = 1;
		bool flag = true;
		while (cnt <= k && head <= n) {
			int r = ask(head, maxv * i);
			if (r == n + 1) {
				flag = false;
				break;
			}
			head = r + 1;
			cnt += 1;
		}
		if (flag && cnt == k + 1 && head == n + 1) {
			cout << "! " << i * maxv << endl;
			cin >> n;
			return;
		}
	}
	cout << "! " << -1 << endl;
	cin >> n;
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
#ifdef LOCAL
    freopen("in.in", "r", stdin);
    freopen("out.out", "w", stdout);
#endif
    int tt; tt = 1;
    cin >> tt;
    while (tt -- ) solve();
    return 0;
}

写在最后:

 

 

 

 


网站公告

今日签到

点亮在社区的每一天
去签到