Codeforces Round #700 (Div. 2) A~C题解
写在前边
A. Yet Another String Game
链接:A题链接
题目大意:
给定一个字符串,有两位同学来操作这个字符串,一个同学负责使得字符串字典序变大,另一个同学负责使得字符串字典序变小,轮到他们的时候他们无论如何都要操作一次,如果当前字符是\('a'\),那么即使轮到了负责使字典序变小的同学来操作,他也要将其变成'b',求最后的字符串。
思路:
模拟即可,遇到\('a'\),\('z'\)字符特判一下。
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <map>
#include <cstring>
using namespace std;
#define Inf 0x3f3f3f3f
#define PII pair<int, int>
#define P2LL pair<long long, long long>
#define endl '\n'
typedef long long LL;
typedef unsigned long long ULL;
typedef vector<long long> VLL;
typedef vector<int> VI;
void solve() {
string s, res = "";
cin >> s;
for (int i = 0; i < s.size(); i++) {
if (i % 2 == 0) { //Alice
res += (s[i] == 'a' ? 'b' : 'a');
} else {
res += (s[i] == 'z' ? 'y' : 'z');
}
}
cout << res << endl;
}
int main()
{
//ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int t;
scanf("%d", &t);
while (t--) {
solve();
}
system("pause");
return 0;
}
B. The Great Hero
链接:B题链接
题目大意:
英雄打怪兽,没有谁先手之分,英雄与怪兽都有血量与攻击力,并且都会收到对方的伤害,攻击的顺序不限,判断最后英雄是否能干掉所有怪兽,即使英雄牺牲也算。
思路:
这种题目常规思路真的很难搞,很容易就出现一些浮点问题,而且还所以不如我们可以先预处理出如果英雄能干掉所有的怪兽所需要的\(HP\)记为\(sum\),然后想,我们如果可以用最少的血量干掉血量多伤害大的怪兽那肯定血赚,比如我们的攻击是\(7\),初始血量为\(8\),这时候有一个攻击力为\(8\)的怪兽,血量为\(7\),如果我们最先攻击这只怪兽,那么我们就与其同归于尽了,其他的怪兽就打不了了,所以收益很低,而我们如果干掉其他所有怪物后再最后攻击这只怪物,还剩下一点血的时候,与其同归于尽收益肯定更大,而这一步排序不容易实现,所以我们可以考虑一下英雄的最后一击,如果英雄的最后一击之前有血量大于\(0\),那么说明英雄就可以完美干掉所有怪物,所以我们可以枚举所有小怪的攻击力,判断\(sum - attack[i] < 英雄HP\)如果出现就说明我们一定可以按照一定的顺序去干掉所有的怪兽,而这个顺序是什么我们不需要在意,时间复杂度\(O(n)\)。
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <map>
#include <cstring>
using namespace std;
#define Inf 0x3f3f3f3f
#define PII pair<int, int>
#define P2LL pair<long long, long long>
#define endl '\n'
typedef long long LL;
typedef unsigned long long ULL;
typedef vector<long long> VLL;
typedef vector<int> VI;
const int N = 1E5 + 10;
int attack[N], hp[N];
int Attack, HP, n;
int cost[N]; //干掉每只怪花的力气
void solve() {
scanf("%d%d%d", &Attack, &HP, &n);
for (int i = 0; i < n; i++) scanf("%d", &attack[i]);
for (int i = 0; i < n; i++) scanf("%d", &hp[i]);
LL sum = 0;
for (int i = 0; i < n; i++) sum += (LL)(hp[i] + Attack - 1) / Attack * attack[i]; //承受攻击
for (int i = 0; i < n; i++) {
if (sum - attack[i] < HP) {
puts("YES");
return;
}
}
puts("NO");
}
int main()
{
//ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int t, cnt = 1;
scanf("%d", &t);
int q = t;
while (t--) {
solve();
}
system("pause");
return 0;
}
C. Searching Local Minimum
链接:C题链接
题目大意:
一道交互题。
思路:
第一次听说这种类型的题目,现在也还是懵懵了,大概就是输出会被机器获取当成输入,输出称为机器的输入,对于这道一而言,我们就是维护一个\([l,r]\)区间最后趋于一个点,并且满足,\(a_{r + 1} > a_r\), \(a_{l - 1} < a_{l}\),这个点就是答案,于是用二分来实现,对于\(a[mid] < a[mid] + 1\),让\(r = mid\),反之\(l = mid + 1\)
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <map>
#include <cstring>
using namespace std;
#define Inf 0x3f3f3f3f
#define PII pair<int, int>
#define P2LL pair<long long, long long>
#define endl '\n'
typedef long long LL;
typedef unsigned long long ULL;
typedef vector<long long> VLL;
typedef vector<int> VI;
LL gcd(LL a, LL b) {
return b ? gcd(b, a % b) : a;
}
const int N = 1E5 + 10;
int a[N];
int n;
void query(int x) {
if (x >= 1 && x <= n) {
printf("? %d\n", x);
fflush(stdout);
scanf("%d", &a[x]);
}
}
void solve() {
scanf("%d", &n);
a[0] = a[n + 1] = 1e9;
int l = 1, r = n;
while (l < r) {
int mid = l + r >> 1;
query(mid);
query(mid + 1);
if (a[mid] < a[mid + 1]) r = mid;
else l = mid + 1;
}
printf("! %d\n", l);
fflush(stdout);
}
int main()
{
//ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
solve();
system("pause");
return 0;
}
另外一道交互题A. Bear and Prime 100.
题目大意:
我们会对系统进行询问,如果我们询问的数是那个隐藏的数的约数,那么系统会回答\(yes\),要求在二十次询问之内,判断出隐藏的数是否为质数,例如:那个隐藏的数为\(14\),那么我们如果打印\(2,7\)或者\(14\),系统都会回答\(yes\)。
思路:
我们要做的就是枚举所有可能的质因数,然后根据系统的回答来判断那个隐藏的数的约数个数,从而判断它是否为约数。
首先根据算术基本定理,如果一个数是合数,那么它一定可以被唯一的分解成两个或两个以上的质数的积,因此最后20次询问之后只需要判断出是否有两个或两个以上的质数,所以我们要做的就是要考虑枚举哪些数才能在确保二十次询问之内判断出一个\(\in [1, 100]\)的数。
首先我们仅仅需要考虑50
之内的质数,因为判断\(n\)是否为质数的一种方式就是枚举到\(\cfrac{n}{2}\)即可,结合实际如果有一个大于\(50\)的质数,那么它与最小的质数相乘也大于\(100\)了,那么现在就有了\(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47\)十五个数。
还要想到一些特例,质数的平方,\(4,9,36,49\)这四个数,所以总共就有\(19\)个数了,因此我们完全可以在\(20\)次询问之内判断出一个数是否为质数了
代码:
#include <cstdio>
#include <vector>
#include <map>
#include <cstring>
using namespace std;
#define Inf 0x3f3f3f3f
#define PII pair<int, int>
#define P2LL pair<long long, long long>
#define endl '\n'
typedef long long LL;
typedef unsigned long long ULL;
typedef vector<long long> VLL;
typedef vector<int> VI;
LL gcd(LL a, LL b) {
return b ? gcd(b, a % b) : a;
}
int primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 4, 9, 25, 49};
void solve() {
int cnt = 0;
char s[10];
for (int i = 0; i < 19; i++) {
cout << primes[i] << endl;
cin >> s;
if (!strcmp(s, "yes")) cnt++;
}
if (cnt >= 2) cout << "composite" << endl;
else cout << "prime" << endl;
}
int main()
{
//ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
solve();
return 0;
}