Codeforces Round 835 (Div. 4)D~G

Codeforces Round 827 (Div. 4)C~G

C. Stripes(思维)

题意

给8 * 8的网格,盖B的话会竖着盖,盖R的话会横着盖。问B还是R最后盖

思路

最后盖的那个肯定可以保留完整的一行/一列(有连续的8格)

代码

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
vector<long long>ans;
void solve() {
	// 看哪一个字母可以连续8个
	int cnt = 0;
	vector<vector<char>>mp(10, vector<char>(10));
	for (int i = 1; i <= 8; i++) {
		for (int j = 1; j <= 8; j++) {
			cin >> mp[i][j];
		}
	}
	for (int i = 1; i <= 8; i++) {
		cnt = 0;
		for (int j = 1; j <= 8; j++) {
			if (mp[i][j] != 'R')break;
			cnt++;
		}
		if (cnt == 8) {
			cout << "R" << endl;
			return;
		}
	}
	for (int i = 1; i <= 8; i++) {
		cnt = 0;
		for (int j = 1; j <= 8; j++) {
			if (mp[j][i] != 'B')break;
			cnt++;
		}
		if (cnt == 8) {
			cout << "B" << endl;
			return;
		}
	}
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int _; _ = 1;
	cin >> _;
	while (_--)	solve();
	for (auto x : ans)cout << x << endl;
	return 0;
}

D. Coprime(gcd,枚举)

题意

给一个数组,从里面取两个下标 i , j(可以相同),使得aiaj的最大公约数是1。问最大的i+j

思路

记录所有出现过的数字,并且保存每一个数字最后出现的下标

数组从后往前枚举数字ai,然后枚举和ai最大公约数为1的数字,看有没有出现在数组里面,尝试更新i+j的最大值,(数据量不大,所以才想到直接枚举的)

代码

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
vector<long long>ans;

int gcd(int a, int b) {
	return b == 0 ? a : gcd(b, a % b);
}

void solve() {
	// 记录每个数字的最后出现位置
	// 从后枚举,看看另一个数字有没有出现,同时尝试更新答案
	int n; cin >> n;
	vector<int>a(n + 1), num, vis(1005), has(1005);
	map<int, int>mp;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		if (!mp.count(a[i])) {
			num.push_back(a[i]);
			has[a[i]] = 1;
		}
		mp[a[i]] = i;
	}

	int res = -1;
	for (int i = n; i >= 1; i--) {
		if (vis[a[i]])continue;
		vis[a[i]] = 1;
		for (int x = a[i]; x >= 1; x--) {
			if (has[x] && gcd(a[i], x) == 1) {
				res = max(res, mp[x] + i);
			}
		}
	}
	ans.push_back(res);
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int _; _ = 1;
	cin >> _;
	while (_--)	solve();
	for (auto x : ans)cout << x << endl;
	return 0;
}

E. Scuza(前缀和,二分,思维)

题意

会先给一个台阶高度的数组kki表示第i个台阶高ki,然后告诉一个腿长aj ?没办法跨过高于aj的台阶,问最多累计跨过多少级台阶

思路

假设我们在kj这个台阶,前面的台阶高度为ki,如果前面的台阶比我们现在所在的台阶高的话,那自然是到不了我们这里的,也累加不了我们的台阶高度。于是我们就可以把当前的台阶高度kj假设为前面最高的台阶(但是实际的高度不变)。于是台阶高度就被我们弄成了不严格递增。也就是假设我们可以跨过ki这个台阶,那么直到下一个比ki高的台阶路上的所有台阶,我们都可以累加。

sum数组记录到第i个台阶,实际累加多少台阶

而数组k就在输入的过程中,如果当前台阶比前面最高的台阶低,那就改为最高的台阶的值

也就是**a[i] = max(a[i],a[i-1]) **

到了询问阶段,给一个高度h的话,说明能跨过的台阶高度不超过h。

因为我们的数组k的单调的,所以可以二分查找到最后一个小于等于h的位置,答案就是这个位置的sum

代码

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
vector<long long>ans;
void solve() {
	int n, q; cin >> n >> q;
	vector<int>a(n + 1);
	vector<long long>sumA(n + 1);
	for (int i = 1; i <= n; i++) {
		cin >> a[i];		
		sumA[i] = sumA[i - 1] + a[i];
		a[i] = max(a[i - 1], a[i]);
	}
	int h;
	while (q--) {
		cin >> h;
		int l = 0, r = n;
		int res = 0, mid;
		while (l <= r) {
			mid = l + r >> 1;
			if (a[mid] <= h) {
				res = mid;
				l = mid + 1;
			}
			else r = mid - 1;
		}
		cout << sumA[res] << " ";
	}
	cout << endl;
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int _; _ = 1;
	cin >> _;
	while (_--)	solve();
	for (auto x : ans)cout << x << endl;
	return 0;
}

F. Smaller(字符串,思维)

题意

s和t初始都是"a",每次会给s或者t加上一些字符串,然后每次都会询问有没有可能通过任意的排序使得字典序s小于t

思路

这题关键是要抓住s和t初始都是"a"

  • 如果t加入了除了a以外的字母

    例如b、c、d……那就可以直接把这些字符放到t的第一位,把a放到s的第一位,变成了

    s:aXXX

    t:bXXX

    字典序s < t

  • 如果t没有加入除了a以外的字母,t全是a

    • s也同样只有字母a

      • t中a的数量 = s中a的数量

        s:aaa

        t:aaa

      • t中a的数量 < s中a的数量

        s:aaaa

        t:aaa

      • t中a的数量 > s中a的数量

        s:aaa

        t:aaaa

      只有第三种情况下,字典序s < t

      否则字典序s > t

    • s中有其他字母

      • t中a的数量 = s中a的数量

        s:aaaX

        t:aaa

      • t中a的数量 > s中a的数量

        s:aaaX

        t:aaaa

      • t中a的数量 < s中a的数量

        s:aaaaX

        t:aaa

      无论如何,字典序s > t

代码

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
vector<long long>ans;
void solve() {
	bool sa = true, ta = true;
	long long lens = 1, lent = 1;
	int q; cin >> q;
	while (q--) {
		int op, k; cin >> op >> k;
		string x; cin >> x;
		if (op == 1) {
			int temp = 0;
			for (char& ch : x) {
				if (ch == 'a')temp++;
				else sa = false;
			}
			lens += x.length() * k;
		}
		if (op == 2) {
			int temp = 0;
			for (char& ch : x) {
				if (ch == 'a')temp++;
				else ta = false;
			}
			lent += x.length() * k;
		}
		// t含有除了a以外的
		if (!ta) {
			cout << "YES" << endl;
			continue;
		}

		// t全为a
		// s全为a
		if (sa) {
			if (lent <= lens) {
				cout << "NO" << endl;
			}
			else cout << "YES" << endl;
		}
		else {
			cout << "NO" << endl;
		}
	}

}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int _; _ = 1;
	cin >> _;
	while (_--)	solve();
	for (auto x : ans)cout << x << endl;
	return 0;
}

G. Orray(位运算)

题意

给了一个数组a,要求前缀或数组b,怎么才能使数组b从第一个数开始就尽可能大(字典序大)

思路

首先想数组b的第一个数字,前缀或的第一个数肯定就只能是它自己。所以数组b的第一个数肯定是最大的那个数字。那后面的数字怎么放?肯定是在所有数字里面挑一个数字或上第一个数字结果最大

那么结果就出来了,每次选的数字,都要尽可能能和前面已经或出来的结果curMax,或出来得到更大的curMax。

并且呢,由于是或运算,curMax最多最多只能达到什么状态?32位都是1的状态,这样后面不论或甚么,都只能得到32位1

所以,挑数字这个操作,最多最多只需要32次,挑完了32次,由于我们每次操作都是尽可能让前缀或尽可能大的(尽量让这个前缀或能再多一位1),如果操作完32次还是没有到32位1的结果。那其实后面想再变大也不行(如果后面继续挑数字能让它变大,那么在前面32次,早就操作过了)

于是只用管前面32个数字排好就行,后面的数字无所谓,于是我们就不会超时(不是O(n2))

代码

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
vector<long long>ans;
void solve() {
	int n; cin >> n;
	int curMax = 0;
	vector<int>a(n), vis(n);
	for (int i = 0; i < n; i++) {
		cin >> a[i];
	}
	// 每次取一个数字,尽量让curMax|a[i]大
	// 最多取32次
	vector<int>tar;
	for (int i = 0; i < min(32, n); i++) {
		int id = -1;
		int newMax = curMax;
		for (int j = 0; j < n; j++) {
			if (vis[j])continue;
			if ((curMax | a[j]) > newMax) {
				newMax = curMax | a[j];
				id = j;
			}
		}
		if (id == -1) {
			break;
		}
		curMax = newMax;
		vis[id] = 1;
		tar.push_back(a[id]);
	}
	for (auto x : tar) {
		cout << x << " ";
	}
	for (int i = 0; i < n; i++) {
		if (vis[i])continue;
		cout << a[i] << " ";
	}
	cout << endl;
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int _; _ = 1;
	cin >> _;
	while (_--)	solve();
	for (auto x : ans)cout << x << endl;
	return 0;
}
posted @ 2025-04-29 02:11  zombieee  阅读(11)  评论(0)    收藏  举报