今天atcoder和cf连续两场,可惜两连战就两连跪。两场都是卡在简单题上了,总觉得思路应该没什么问题,就是某些小的点可能没考虑到。来看看这两场吧
A - Content Too Large
思路:给定n个物品的大小,以及一个背包的大小,问背包是否够大。这就是个水题,求个和即可判定。不过这次,又在YES和Yes大小写的问题上栽跟头了,屡教不改,总是在同一个坑摔更头可不是个好现象。3min第一WA,等到第二题做完,14min才转头再次提交,也是浪费了不少时间。
cpp
/*
Author Owen_Q
*/
#include <bits/stdc++.h>
using namespace std;
int main() {
ios_base::sync_with_stdio(false), cin.tie(nullptr);
int n, m;
cin >> n >> m;
int sum = 0;
for (int i = 0; i < n; i++) {
int a;
cin >> a;
sum += a;
}
if (sum > m) {
cout << "No" << endl;
} else {
cout << "Yes" << endl;
}
return 0;
}
B - cat 2
思路:给定n个字符串,要求字符串俩俩拼接,求能拼接出多少种不同的新字符串
水题一个,存储字符串然后拼接后往set里扔。一开始是读字符串没读出来,后面又忘记了两个字符串可以前后拼接两次,反正小问题不断,13min才ac,本题用时10min
cpp
/*
Author Owen_Q
*/
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 105;
string v[MAXN];
int main() {
ios_base::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> v[i];
}
set<string> col;
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
string s = v[i] + v[j];
col.insert(s);
s = v[j] + v[i];
col.insert(s);
// cout << i << "*" << j << "*" << v[i] << "*" << v[j] << "*" << s << "*" << col.size() << endl;
}
}
cout << col.size() << endl;
return 0;
}
C - Large Queue
思路:给定入队和出队操作,入队可以一次入c个相同的数,出队可以连续出k个数并求和,要求模拟过程。这也是水题,用两个数组分别记录队列重复的数量和重复值,出队的时候修改每一位的剩余值并求和就可以了,细节点注意一下变量值的维护,避免死循环,真的离谱,还能犯这种错。27min搞定,本题用时13min
cpp
/*
Author Owen_Q
*/
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;;
typedef long long ll;
int cc[MAXN];
int xx[MAXN];
int main() {
ios_base::sync_with_stdio(false), cin.tie(nullptr);
int q;
cin >> q;
int current = 0, pos = 0;;
while (q--) {
int p;
cin >> p;
if (p == 1) {
int c, x;
cin >> c >> x;
cc[pos] = c;
xx[pos++] = x;
} else {
int k;
cin >> k;
ll re = 0;
while (k > 0) {
if (cc[current] <= k) {
re += (ll) xx[current] * (ll) cc[current];
k -= cc[current];
current++;
} else {
re += (ll) xx[current] * (ll) k;
cc[current] -= k;
k = 0;
}
}
cout << re << endl;
}
}
return 0;
}
D - Make Geometric Sequence
思路:给定n个数,问这n个数能否成为等比数列。卡题卡题疯狂卡题,第一次提交只花费了21min,但是卡题卡了整整46min,一直卡到比赛结束还没卡出来,看看吧,这题到底错哪里了。
这题我的思路就是先按照绝对值排序,排完后,求相邻两数的公比,并判别符号,最后特殊注意一下,所有数绝对值都一样的场景,要求要么符号都一样,要么不同符号差最大为1。
看不出来这题哪里出问题了,重写。这题的重心就在绝对值相同和绝对值不同等差两种情况。
于是先特判绝对值相同的场景,然后对负数进行计数
针对常规场景,有两个小技巧,一是可以重写cmp函数,做到按照绝对值排序切不丢失原有符号。二是在判断等比的时候,化除法为乘法,可以避免精度丢失,妥妥AC
cpp
/*
Author Owen_Q
*/
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
int a[MAXN];
typedef long long ll;
bool cmp(int a, int b) {
return abs(a) < abs(b);
}
int main() {
ios_base::sync_with_stdio(false), cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
cin >> a[0];
bool allSame = true;
bool ok = true;
int minus = a[0] < 0 ? 1 : 0;
for (int i = 1; i < n; i++) {
cin >> a[i];
if (abs(a[i]) != abs(a[0])) {
allSame = false;
}
if (a[i] < 0) {
minus++;
}
}
sort(a, a + n, cmp);
if (allSame) {
if (n % 2 == 0 && (minus != n / 2 && minus != n && minus != 0)) {
ok = false;
}
if (n % 2 == 1 && (minus != n / 2 && minus != n / 2 + 1 && minus != n && minus != 0)) {
ok = false;
}
} else {
for (int i = 2; i < n; i++) {
if ((ll) a[i - 2] * (ll) a[i] != (ll) a[i - 1] * (ll) a[i - 1]) {
ok = false;
break;
}
}
}
if (ok) {
cout << "Yes" << endl;
} else {
cout << "No" << endl;
}
}
return 0;
}
const double eps = 1e-5;
set<int> maset;
set<int> allset;
int mainWA() {
ios_base::sync_with_stdio(false), cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
maset.clear();
int mdc = 0;
int mda = -1;
bool ok = true;
bool hasSame = false;
for (int i = 0; i < n; i++) {
cin >> a[i];
if (a[i] < 0) {
a[i] = -a[i];
if (allset.contains(a[i])) {
if (hasSame == false && maset.contains(a[i])) {
// 当首个是负数第二个也是负数时,补上首个的负数
mdc++;
}
if (mda == -1 || mda == a[i]) {
mda = a[i];
mdc++;
} else {
ok = false;
}
hasSame = true;
} else {
maset.insert(a[i]);
}
} else {
if (allset.contains(a[i])) {
if (hasSame == false && maset.contains(a[i])) {
// 当首个是负数第二个是正数时,补上首个的负数
mdc++;
}
hasSame = true;
}
}
allset.insert(a[i]);
}
if (ok) {
sort(a, a + n);
int a0 = a[0];
int a1 = a[1];
double diff = (double) a1 / (double) a0;
bool m0 = maset.contains(a0);
bool m1 = maset.contains(a1);
bool samem = m1 == m0;
for (int i = 2; i < n; i++) {
int ai = a[i];
bool mi = maset.contains(ai);
double diffa = diff - (double) ai / (double) a1;
if (diffa > eps || diffa < -eps) {
ok = false;
break;
}
if (samem != (mi == m1)) {
ok = false;
break;
}
a1 = ai;
m1 = mi;
}
}
if (ok && mdc > 0) {
if (n % 2 == 0 && (mdc != n / 2 && mdc != n)) {
ok = false;
}
if (n % 2 == 1 && (mdc != n / 2 && mdc != n / 2 + 1 && mdc != n)) {
ok = false;
}
}
if (ok) {
cout << "Yes" << endl;
} else {
cout << "No" << endl;
}
}
return 0;
}
// 2
// 4
// 1 1 -1 1
// 2
// -2 -2
E - Reverse 2^i
思路:给定一个数串,可以将其拆分成段,每段内可以进行翻转,求翻转后的最小串。
其实这一题也很好想,既然他说了这个段长,那么我们就按照这个段长来进行模拟。从小到大,每次对比相邻两个串进行合并,判断最小值在哪个串内,若在前串则不用动,若在后串,则分别将两串翻转后,合并,再将合并后的串翻转。
cpp
/*
Author Owen_Q
*/
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 3e5 + 5;
int p[MAXN];
void compareAndReverse(int pos, int len) {
// cout << "len=" << len << "pos=" << pos << " ";
// for (int i = 0; i < 2 * len; i++) {
// cout << p[i] << " ";
// }
// cout << endl;
int min1 = p[pos];
int min2 = p[pos + len];
for (int i = 1; i < len; i++) {
min1 = min(min1, p[pos + i]);
min2 = min(min2, p[pos + len + i]);
}
if (min1 > min2) {
reverse(p + pos, p + pos + len);
reverse(p + pos + len, p + pos + len + len);
reverse(p + pos, p + pos + len + len);
}
// for (int i = 0; i < 2 * len; i++) {
// cout << p[i] << " ";
// }
// cout << "after" << endl;
}
int main() {
ios_base::sync_with_stdio(false), cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
int maxn = 1;
for (int i = 0; i < n; i++) {
maxn *= 2;
}
for (int i = 0; i < maxn; i++) {
cin >> p[i];
}
for (int len = 1; len < maxn; len *= 2) {
for (int pos = 0; pos + len * 2 <= maxn; pos += len * 2) {
compareAndReverse(pos, len);
}
}
for (int i = 0; i < maxn; i++) {
cout << p[i] << " ";
}
cout << endl;
}
return 0;
}
这一题一开始被边界的问题闹得晕晕乎乎,实际数组大小其实为指数级,但由于上限限制了最大数量级避免的数组不会越界。还是写的时候需要脑子清楚呀。这一题比赛结束后36min过,比前一题还顺利。