A Three Indices
题意
给你一个 (1-n) 的排列 (p),让你找到三个数 (i,j,k) 使得 $p_i < p_j $ 且 (p_j > p_k)。
解析
先从前往后扫一遍,求出哪些位置满足存在一个比它小的在它前面。这可以用树状数组统计当前 (1-i) 中出现了几个。
然后倒着在做一遍求出哪些位置存在一个比它小的在它后面。
找到一个都满足的点,然后在它前面和后面都找一个比它小的即可。
若不存在即为没有。
#include <bits/stdc++.h>
using namespace std;
int t;
int n;
int a[1010];
int c[1010];
bool mark[1010], ans;
int pos;
int lowbit(int x){return x & -x;}
void add(int x) {
while (x <= n) {
c[x]++;
x += lowbit(x);
}
}
int ask(int x) {
int ret = 0;
while (x) {
ret += c[x];
x -= lowbit(x);
}
return ret;
}
int main() {
cin >> t;
while (t--) {
ans = 0;
cin >> n;
for (int i = 1; i <= n; i++) c[i] = 0, mark[i] = 0;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) {
if (ask(a[i] - 1)) {
mark[i] = 1;
}
add(a[i]);
}
for (int i = 1; i <= n; i++) c[i] = 0;
for (int i = n; i; i--) {
if (mark[i] && ask(a[i] - 1)) {
pos = i;
ans = 1;
break;
}
add(a[i]);
}
if (ans) {
puts("YES");
for (int i = 1; i < pos; i++) {
if (a[i] < a[pos]) {
cout << i << " ";
break;
}
}
cout << pos << " ";
for (int i = pos + 1; i <= n; i++) {
if (a[i] < a[pos]) {
cout << i << endl;
break;
}
}
} else puts("NO");
}
return 0;
}
D Berserk And Fireball
解析
我们先在 (a) 中找到 (b),把这些位置标记下来,如果找不到则无解。
然后对于每两个标记的数之间我们统计有多少个数((0)号位和(n+1)号位视为被标记的)。
如果这个值小于 (k) 的话,我们只能 Berserk 把它们干掉,而如果这些数的最大值大于两端点标记的数的最大值则无解。所以我们还需记录这个最大值。
如果这个值大于 (k) 的话则一定有解。
分成两种情况:
1、(y imes k < x)
这种情况用 (k) 次 Berserk 比用一次 Fireball 更优。
但是最后不用 Fireball 可能干不掉全部的,所以我们要特判这种情况。
如果最大值比两端点都要小,则不需要用 Fireball,一直用 Berserk 就行。
否则我们一定要用一次 Fireball 把最大的干掉。剩下的全部用 Berserk。
2、(y imes k ge x)
这种情况用 Fireball 更优,但是可能会出现剩余的情况,所以在用 Fireball 之前先用 Berserk 干到是 (k) 的倍数就行。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 200010;
ll n, m;
ll x, y, k;
ll a[N], b[N];
ll top = 1;
bool mark[N];
ll ans, cnt, mx;
int main() {
cin >> n >> m;
cin >> x >> k >> y;
for (ll i = 1; i <= n; i++) cin >> a[i];
for (ll i = 1; i <= m; i++) cin >> b[i];
for (ll i = 1; i <= n; i++) {
if (a[i] == b[top]) {
mark[i] = 1;
top++;
}
}
if (top < m) puts("-1");
else {
int lst = 0;
mark[n + 1] = 1;
for (int i = 1; i <= n + 1; i++) {
if (mark[i]) {
cnt = i - lst - 1;
if (cnt == 0) {
lst = i;
mx = 0;
continue;
}
if (cnt < k) {
if (mx < max(a[lst], a[i])) {
ans += y * cnt;
} else {
puts("-1");
return 0;
}
} else {
if (y * k < x) {
if (mx < max(a[lst], a[i])) {
ans += y * cnt;
} else {
ans += y * (cnt - k) + x;
}
} else {
ans += cnt / k * x + (cnt % k) * y;
}
}
lst = i;
mx = 0;
} else {
mx = max(mx, a[i]);
}
}
cout << ans;
}
return 0;
}