首先,題面簡短,是道思維好題。我們仔細想想,可以先推出幾個簡單但正確的性質。
-
如果當前最強蛇吃了最弱蛇後,不是最弱,那麼一定可以吃。(簡要證明:因為吃後不是最弱,所以如果原先次強蛇選擇吃,那麼他會成為比原先最強蛇消弱後更弱的蛇。因為每一條蛇都會選擇最優策略,都不想被吃,那麼如果原先次強蛇選擇吃,就能保證他不會死,那麼比他強的原先最強蛇也不會死;如果原先次強蛇不吃,那麼遊戲結束,依舊不會死)。
-
在保證1成立的基礎上,生成的新蛇越來越弱(易證)。
那麼唯一的問題就是如果最強蛇吃了後,變成了最弱,那麼這個決策是否有執行的必要?
這是本道題的第二階段。
我們可以遞迴地思考問題,如果下一條決策蛇吃了原蛇後不是最弱,他肯定會吃。如果下一條決策蛇吃了原蛇後,只剩他自己,他也肯定會吃。其餘情況遞迴解決。至於程式實現,就是迭代。我們也只要注意遞迴次數奇偶性,因為決策優劣性是交替的。
那麼問題迎刃而解,你認為你AC了,可是你發現你TLE了!
原來這題卡 $O(nlog_2n)$ 的做法,不能用set亂搞。
我們想起來有一年NOIp考了一題叫蚯蚓,也是卡$O(nlog_2n)$ 的做法。那道題,我們發現了單調性,用佇列做好的。
你難道以為題目中輸入資料的單調性是沒用的嗎?
根據性質2,在第一階段,生成蛇有單調性,所以直接兩個佇列維護。一個維護原蛇,另一個維護變蛇,都是單調的。
第二階段同理,只要注意最後判斷的細節就好啦!
code:
// Program written by Liu Zhaozhou ~~~
#include <bits/stdc++.h>
using namespace std;
inline char gc(void) {
static char buf[100000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}
template <class T> inline void read(T &x) {
T f = 1; x = 0; static char c = gc();
for (; !isdigit(c); c = gc()) if (c == '-') f = -f;
for (; isdigit(c); c = gc()) x = (x << 1) + (x << 3) + (c & 15);
x *= f;
}
inline void readstr(char *s) {
do *s = gc(); while ((*s == ' ') || (*s == '\n') || (*s == '\r'));
do *(++s) = gc(); while ((~*s) && (*s != ' ') && (*s != '\n') && (*s != '\r'));
*s = 0; return;
}
inline void readch(char&x) { while (isspace(x = gc())); }
char pf[100000], *o1 = pf, *o2 = pf + 100000;
#define ot(x) (o1 == o2 ? fwrite(pf, 1, 100000, stdout), *(o1 = pf) ++= x : *o1 ++= x)
template <class T>
inline void println(T x, char c = '\n') {
if (x < 0) ot(45), x = -x;
static char s[15], *b; b = s;
if (!x) *b ++= 48;
for (; x; * b ++= x % 10 + 48, x /= 10);
for (; b-- != s; ot(*b)); ot(c);
}
template <class T> inline void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + 48);
}
template <class T> inline void writeln(T x, char c = '\n') { write(x); putchar(c); }
template <class T> inline void chkmax(T &x, const T y) { x > y ? x = x : x = y; }
template <class T> inline void chkmin(T &x, const T y) { x < y ? x = x : x = y; }
#define Ms(arr, opt) memset(arr, opt, sizeof(arr))
#define Mp(x, y) make_pair(x, y)
typedef long long ll;
typedef pair <int, int> pii;
const int Maxn = 1e6 + 5;
int T, n, a[Maxn];
inline int solve(void) {
deque <pii> q1, q2; int ret = 0;
for (int i = 1; i <= n; i++) q1.push_back(Mp(a[i], i));
while (true) {
if (q1.size() + q2.size() == 2) return 1;
int x, y, idx; y = q1.front().first; q1.pop_front();
if (q2.empty() || (!q1.empty() && q1.back() > q2.back())) {
x = q1.back().first; idx = q1.back().second; q1.pop_back();
} else {
x = q2.back().first; idx = q2.back().second; q2.pop_back();
} pii cur = Mp(x - y, idx);
if (q1.empty() || q1.front() > cur) {
ret = (int) q1.size() + (int) q2.size() + 2; int cnt = 0;
while (true) {
++cnt;
if ((int) q1.size() + (int) q2.size() == 1) {
if (cnt % 2 == 0) --ret; break;
}
int x, idx;
if (q2.empty() || (!q1.empty() && q1.back() > q2.back())) {
x = q1.back().first; idx = q1.back().second; q1.pop_back();
} else {
x = q2.back().first; idx = q2.back().second; q2.pop_back();
}
cur = Mp(x - cur.first, idx);
if (!((q1.empty() || cur < q1.front()) && (q2.empty() || cur < q2.front()))) {
if (cnt % 2 == 0) --ret; break;
}
} break;
} else q2.push_front(cur);
} return ret;
}
signed main(void) {
read(T);
for (int i = 1; i <= T; i++) {
if (i == 1) {
read(n);
for (int j = 1; j <= n; j++) read(a[j]);
} else {
int k; read(k);
for (int j = 1, x, y; j <= k; j++)
read(x), read(y), a[x] = y;
} writeln(solve());
}
// fwrite(pf, 1, o1 - pf, stdout);
return 0;
}
/**/