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
题目链接:
题面:
题目大意:
给一个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
题目链接:
题面:
题目大意:
给一个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
题目链接:
题面:
题目大意:
给定一个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
题目链接:
题面:
题目大意:
有一个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
题目链接:
题面:
题目大意:
有两个字符串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
题目链接:
题面:
题目大意:
给定一个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;
}