模擬題

EternalEpic發表於2024-06-26

首先,題面簡短,是道思維好題。我們仔細想想,可以先推出幾個簡單但正確的性質。

  1. 如果當前最強蛇吃了最弱蛇後,不是最弱,那麼一定可以吃。(簡要證明:因為吃後不是最弱,所以如果原先次強蛇選擇吃,那麼他會成為比原先最強蛇消弱後更弱的蛇。因為每一條蛇都會選擇最優策略,都不想被吃,那麼如果原先次強蛇選擇吃,就能保證他不會死,那麼比他強的原先最強蛇也不會死;如果原先次強蛇不吃,那麼遊戲結束,依舊不會死)。

  2. 在保證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;
}

/**/


相關文章