B题
题意
你有一个英雄,攻击力为A,生命值为B。(没有经验、金币等机制,攻击力与生命值不可提高)
游戏中有n只怪,怪的攻击力为a[i],生命值为b[i]。
每次你可以选择一个怪攻击,攻击后你的生命值变为B-a[i],怪的生命值变为b[i]-A。
不论你是否死亡,如果你能消灭所有的怪,获得胜利。否则失败。
题解
别想复杂,模拟即可
由于最后,不管英雄死活,只要怪全死就好了,对于杀死所有怪物的最后一刀,只要当时英雄血量大于0,就好了
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 1e9 + 7;
const int MAX = 1e5 + 10;
ll a[MAX];
ll b[MAX];
int main() {
int T;
scanf("%d", &T);
while(T--) {
ll A, B, n;
scanf("%lld%lld%lld", &A, &B, &n);
ll max_damage = 0;
for(int i = 0; i < n; i++) {
scanf("%lld", &a[i]);
max_damage = max(max_damage, a[i]);
}
for(int i = 0; i < n; i++) scanf("%lld", &b[i]);
for(int i = 0; i < n; i++) {
B -= (b[i] + A - 1) / A * a[i];
}
if(B + max_damage > 0) printf("YES\n");
else printf("NO\n");
}
}
C题
题意
交互题,输入一个n,会有一个序列(序列中的数就是1…n乱序排列),然后你可以询问最多100次,来找出序列中一个局部最小值(就是这个数小于它左右两边的数)
题解
原本我找三个判断趋势,实际上最多寻找100次,1e5刚刚好卡住34次,每次找三个,最多只能找33次。
呜呜呜
其实a[0] = a[n+1] = INF,就暗示了,头是递减,尾是递增,任意找两个,如果是递增,那么与头就一定有最小极值点,同理。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
using namespace std;
const int MAX = 1e5 +10;
const int INF = 1e9 + 7;
int a[MAX];
int main(){
int n;
scanf("%d", &n);
int L = 1, R = n;
a[0] = INF, a[n + 1] = INF;
int mid;
for(int i = 0; i < 100; i++) {
int mid = (L + R) / 2;
printf("? %d\n", mid);
fflush(stdout);
scanf("%d", &a[mid]);
if(mid + 1 <= n) {
printf("? %d\n", mid + 1);
fflush(stdout);
scanf("%d", &a[mid + 1]);
}
if(L == R) {
printf("! %d\n", L);
break;
}
if(a[mid] < a[mid + 1]) R = mid;
else L = mid + 1;
}
}
D1题目
题意
把一个长度为n的数组分成两个子数组a,b,要求seg(a)+seg(b) 最大 ,seg(a)表示数组中不同的连续段,例如[1,1,2,2,3,3,3,1] 连续段就是[1,2,3,1] 长度是4
题解
这道题目想明白关键点是尽可能少出现连续一样的,那么其实只需要关注每个数组的最后一个值
设数组1的最后一个值为v1, 数组2的最后一个值为v2
1.如果要插入的值a,不等于v1,v2,且v1 = v2那么任意插
2.如果与v1 或者 v2相等,那就插到不想等的后面去
3.如果都不相等,要使得再次出现v1或者v2时,v1或者v2已经被替换掉,所以先替换掉v1、v2中在待插入的数组中先出现的。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
using namespace std;
const int MAX = 1e5 +10;
const int INF = 1e9 + 7;
vector<int>pos[MAX];//每个数字出现的位置
int cnt[MAX];//每个数字出现了几次
int a[MAX];
int main(){
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++) {
scanf("%d", &a[i]);
pos[a[i]].push_back(i);
}
int v1 = -1, v2 = -1;
ll ans = 0;
for(int i = 0; i < n; i++) {
cnt[a[i]]++;
if(v1 == v2) {
if(a[i] != v1) {
v1 = a[i];
ans++;
}
}
else if(v1 == a[i] && v2 != a[i]) {
v2 = a[i];
ans++;
}
else if(v2 == a[i] && v1 != a[i]) {
v1 = a[i];
ans++;
}
else {
int next_v1 = n + 1, next_v2 = n + 1;
if(cnt[v1] < pos[v1].size()) {
next_v1 = pos[v1][cnt[v1]] ;
}
if(cnt[v2] < pos[v2].size()) {
next_v2 = pos[v2][cnt[v2]];
}
if(next_v1 < next_v2) {
v1 = a[i];
ans++;
}
else {
v2 = a[i];
ans++;
}
}
}
printf("%lld\n", ans);
}
D2题目
题意
与D1相似,问最小
题解
与上题目类似,改一点点就好了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
using namespace std;
const int MAX = 1e5 +10;
const int INF = 1e9 + 7;
vector<int>pos[MAX];
int a[MAX];
int cnt[MAX];
int main(){
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++) {
scanf("%d", &a[i]);
pos[a[i]].push_back(i);
}
int v1 = -1, v2 = -1;
ll ans = 0;
for(int i = 0; i < n; i++) {
cnt[a[i]]++;
if(v1 == v2) {
if(v1 != a[i]) {
v1 = a[i];
ans++;
}
}
else if(v2 != a[i] && v1 == a[i]) {
v1 = a[i];
}
else if(v1 != a[i] && v2 == a[i]) {
v2 = a[i];
}
else {
int next_v1 = n + 1, next_v2 = n + 1;
if(cnt[v1] < pos[v1].size()) {
next_v1 = pos[v1][cnt[v1]];
}
if(cnt[v2] < pos[v2].size()) {
next_v2 = pos[v2][cnt[v2]];
}
if(next_v1 < next_v2) {
v2 = a[i];
ans++;
}
else {
v1 = a[i];
ans++;
}
}
}
printf("%lld\n", ans);
}
总结
B题卡住了,出的太慢;想复杂了呀,唉,应该想到AB题怎么可能出的难呢!!
C题目交互题,没有经验,所以想复杂了,明明是简单的二分,呜呜呜,笨蛋啊
D1想明白问题的关键,其实不难
D2完完全全与D1类似啊,一点也不难,呜呜呜