Codeforces Round #827 (Div. 4) A ~ G

A. Sum

题目链接:

Problem - A - Sum

题面:

在这里插入图片描述

题目大意:

给定a,b,c三个数,判断是否存在其中一个数是另两个数之和

思路:

模拟

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 3e5 + 10;
const ll mod = 1e11 + 3;
const double PI = acos(-1);
#define IOS std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
void solve() {
	int a, b, c;
	cin >> a >> b >> c;
	if (a == b + c || b == a + c || c == a + b) cout << "YES\n";
	else cout << "NO\n";
}
int main() {
	IOS;
	int t;
	cin >> t;
	while (t--) {
		solve();
	}
	return 0;
}

B.Increasing

题目链接:

Problem - B - Increasing

题面:

在这里插入图片描述

题目大意:

给一个n个元素的数组,判断经过随意排序后能否成为一个严格单调递增的数组。

思路:

排序,遍历

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 3e5 + 10;
const ll mod = 1e11 + 3;
const double PI = acos(-1);
#define IOS std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
int a[MAX];
void solve() {
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	sort(a + 1, a + 1 + n);
	for (int i = 2; i <= n; i++) {
	    if (a[i] <= a[i - 1]) {
	        cout << "NO\n";
	        return ;
	    }
	}
	cout << "YES\n";
}
int main() {
	IOS;
	int t;
	cin >> t;
	while (t--) {
		solve();
	}
	return 0;
}

C.Stripes

题目链接:

Problem - C - Stripes

题面:

在这里插入图片描述

题目大意:

给一个8 * 8的空白矩阵,对其填色,其中蓝色只能一次填一列,红色只能一次填一行,并且原来有颜色的格子再次填色后原来的颜色会被覆盖。现给定矩阵的最后颜色分布,求最后填的颜色。

思路:

遍历行和列,找到某一行或某一列有一样的颜色,该颜色即为答案(注意判断是否为无色)。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 3e5 + 10;
const ll mod = 1e11 + 3;
const double PI = acos(-1);
#define IOS std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
char c[10][10];
void solve() {
	for (int i = 1; i <= 8; i++) {
		for (int j = 1; j <= 8; j++) {
			cin >> c[i][j];
		}
	}
	//判断行	 
	for (int i = 1; i <= 8; i++) {
		int flag = 1;
		for (int j = 1; j <= 8; j++) {
			if (c[i][j] != 'R') {
				flag = 0;
				break;
			}
		}
		if (flag && c[i][1] != '.') {
			cout << c[i][1] << "\n";
			return ;
		}
	}
	//判断列 
	for (int j = 1; j <= 8; j++) {
		int flag = 1;
		for (int i = 1; i <= 8; i++) {
			if (c[i][j] != 'B') {
				flag = 0;
				break;
			}
		}
		if (flag && c[1][j] != '.') {
			cout << c[1][j] << "\n";
			return ;
		}
	}
}
int main() {
	IOS;
	int t;
	cin >> t;
	while (t--) {
		solve();
	}
	return 0;
}

D.Coprime

题目链接:

Problem - D- Coprime

题面:

在这里插入图片描述

题目大意:

给定一个n个元素的数组,该数组的价值为数组内两个互为质数的值的下标之和的最大值,求价值。若数组内不存在两个互为质数的值,则输出-1.

思路:

由于数组的值域为[1,1000],可以先进行预处理,得到与[1,1000]的值互为质数的值,然后进行判断。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 2e5 + 10;
const ll mod = 1e11 + 3;
const double PI = acos(-1);
#define IOS std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
int gcd(int a, int b) {
	if (a % b == 0) return b;
	else return gcd(b, a % b);
}
vector<int>vc[1005];
int a[MAX], cnt[1005];
void solve() {
	memset(a, 0, sizeof a);
	memset(cnt, 0, sizeof cnt);
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		cnt[a[i]] = i;
	}
	int ans = -1;
	for (int i = 1; i <= n; i++) {
		for (auto it : vc[a[i]]) {
			if (cnt[it]) ans = max(ans, i + cnt[it]);
		}
	}
	cout << ans << "\n";
}
int main() {
	IOS;
	int t;
	cin >> t;
	for (int i = 1; i <= 1000; i++) {
		for (int j = i; j <= 1000; j++) {
			if (gcd(i, j) == 1) {
				vc[i].push_back(j);
				vc[j].push_back(i);
			}
		}
	}
	while (t--) {
		solve();
	}
	return 0;
}

E.Scuza

题目链接:

Problem - E - Scuza

题面:

在这里插入图片描述

题目大意:

有一个n级的台阶,每级台阶的高度不同,当一个人的腿长大于等于台阶当前级的高度时,则能够登上这级台阶。有q个腿长,问每个腿长能够登上台阶的高度是多少。

思路:

方法一:二分答案。二分能够登上第几级台阶。先要预处理出,对每级台阶的高度求前缀和,然后求出登上这级台阶所需要的最小腿长,即min = max(a[1],a[2],a[3]…a[i])
方法二:先记录每个腿长k[i],对k进行从小到大排序,设置遍历初始位置pos所以我们遍历数组a,设每个k[i]能够登上的台阶高度为sum[i],可以得到,当a[pos] <= k[i]时,sum[i] += a[pos]。因为腿长大的能够登上台阶的高度必然大于等于腿长小的,所以sum[i]的初始值等于sum[i - 1],而当pos > n 时,代表之后的腿长都能够到达的高度均为台阶的总高度。

代码:

方法一:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 2e5 + 10;
const ll mod = 1e11 + 3;
const double PI = acos(-1);
#define IOS std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
ll a[MAX], sum[MAX], Max[MAX], k;;
bool judge(int x) {
	if (k >= Max[x]) return true;
	else return false;
}
void solve() {
	int n, q;
	cin >> n >> q;
	sum[0] = 0;
	Max[0] = 0;
	map<ll, int> mp;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		sum[i] = sum[i - 1] + a[i];
		Max[i] = max(Max[i - 1], a[i]);
		mp[sum[i]] = i;
	}
	while (q--) {
		cin >> k;
		int l = 0, r = n;
		while (l <= r) {
			ll mid = (l + r) / 2;
			if (judge(mid)) l = mid + 1;
			else r = mid - 1;
		}
		cout << sum[l - 1] << " ";
	}
	cout << "\n";
}
int main() {
	IOS;
	int t;
	cin >> t;
	while (t--) {
		solve();
	}
	return 0;
}

方法二:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 2e5 + 10;
const ll mod = 1e11 + 3;
const double PI = acos(-1);
#define IOS std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
ll a[MAX], sum[MAX];
struct ty{
	int pos, num;
}k[MAX];
bool comp(ty a, ty b) {
	return a.num < b.num;
}
void solve() {
	int n, q;
	cin >> n >> q;
	memset(sum, 0, sizeof sum);
	for (int i = 1; i <= n; i++) {
		cin >>a[i];
	}
	int pos = 1;
	for (int i = 1; i <= q; i++) {
		cin >> k[i].num;
		k[i].pos = i;
	}
	sort(k + 1, k + 1 + q, comp);
	for (int i = 1; i <= q; i++) {
		sum[k[i].pos] = sum[k[i - 1].pos]; 
		while (pos <= n) {
			if (k[i].num >= a[pos]) {
				sum[k[i].pos] += a[pos];
				pos++;
			} else break;
		}
	}
	for (int i = 1; i <= q; i++) cout << sum[i] << " ";
	cout << "\n";
}
int main() {
	IOS;
	int t;
	cin >> t;
	while (t--) {
		solve();
	}
	return 0;
}

方法一:在这里插入图片描述
方法二:在这里插入图片描述

个人觉得方法一更容易理解,更容易想到,但是在赛时我想到的是方法二,赛后躺在床上突然想到能用二分。

F.Smaller

题目链接:

Problem - F - Smaller

题面:

在这里插入图片描述

题目大意:

有两个字符串s和t,初值都为"a",对两个字符串执行q次操作,当k=1时,在s后添加d个字符串str,当k=2时,对t进行上述操作。问每次操作,能否在
对字符串s和t随意变换后,使得s的字典序严格小于t。

思路:

通过题面我们可以知道,每次我们能够打乱两个字符串的字符顺序,那么我们只需使字符串s的字典序尽可能小,使字符串t的字典序尽可能大,再判断此时s和t的字典序大小。而我们不可能真的模拟出上述操作,因为是O(n^2),n为字符串长度。其实只要再想想,因为字符串s和t的初值都为"a",那么变换顺序后字符串s的第一位一定是"a",而如果字符串t内包含的字符有除"a"外的字符,那么只需将这个字符放到t的第一位则能够做到s的字典序小于t。而如果t仅由字符"a"组成,那么需要判断s和t中"a"的个数。如果s中的个数多,那么s的字典序不可能比t大,因为"aa"的字典序比"a"大。如果s中的个数少,那么判断s是否仅为"a"组成,若仅为"a"组成则可能,反之则不可能。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 2e5 + 10;
const ll mod = 1e11 + 3;
const double PI = acos(-1);
#define IOS std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
ll a[30], b[30];
void solve() {
	int n;
	cin >> n;
	memset(a, 0, sizeof a);
	memset(b, 0, sizeof b);
	a[1] = 1, b[1] = 1;
	ll len1 = 1, len2 = 1;
	for (int i = 1; i <= n; i++) {
		int k;
		ll d;
		string s;
		cin >> k >> d >> s;
		if (k == 1) {
			for (int j = 0; j < s.length(); j++) {
				a[s[j] - 'a' + 1] += d;
				len1 += d;
			}
		} else if (k == 2) {
			for (int j = 0; j < s.length(); j++) {
				b[s[j] - 'a' + 1] += d;
				len2 += d;
			}
		}
		int max2 = 0, flag = 0;
		for (int i = 2; i <= 26; i++) {
			if (b[i] > 0) {
				cout << "YES\n";
				flag = 1;
				break;
			}
		}
		if (!flag) {
			if (a[1] < b[1] && len1 == a[1]) {
				cout << "YES\n";
			} else cout << "NO\n";
		}
	}
}
int main() {
	IOS;
	int t;
	cin >> t;
	while (t--) {
		solve();
	}
	return 0;
}

G.Orray

题目链接:

Problem - G - Orray

题面:

在这里插入图片描述

题目大意:

给定一个n个元素的数组a,数组b的值bi=a1 or a2 or a3 or… ai。求通过改变数组a的元素顺序得到的字典序最大的数组b。

思路:

有题意可知b[i] = (b[i - 1] | a[i])。要使数组b的字典序最大,那么需要对a[i]进行排序,因为数组a的值域为[1,1e9]那么最多只需要排序30次即可(2^30)。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 2e5 + 10;
const ll mod = 1e11 + 3;
const double PI = acos(-1);
#define IOS std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
int a[MAX];
bool used[MAX];
void solve() {
	int n;
	cin >> n;
	memset(used, 0, sizeof used);
	for (int i = 1 ; i <= n; i++) {
		cin >> a[i];
	}
	int now = 0;
	for (int i = 1; i <= min(n, 30); i++) {
		int Max = -1, id = -1;
		for (int j = 1; j <= n; j++) {
			if (used[j]) continue;
			if (Max < (now | a[j])) {
				Max = (now | a[j]);
				id = j;
			}
		}
		cout << a[id] << " ";
		used[id] = true;
		now |= a[id];
	}
	for (int i = 1; i <= n; i++) {
		if (used[i]) continue;
		cout << a[i] << " ";
	}
	cout << "\n";
}
int main() {
	IOS;
	int t;
	cin >> t;
	while (t--) {
		solve();
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值