- 题解
贪吃蛇 题解
- @ 2024-9-25 20:05:51
我们要想到吃的过程应该是唯一确定的,而不是枚举出来的。
y ................................ x
性质1:一条蛇吃完最弱的蛇后,如果不会变成最弱的蛇,那么它一定不会死,所以它必然会吃。
证明: 情况1:x吃完y后,仍然最强,x必然可以吃y
情况2:x吃完y后,不是最强的,x必然可以吃y
性质2:分类讨论,一条蛇吃完最弱的蛇后,自己变得最弱。
此时,吃不吃取决于下条最强的蛇。
y y1 ................. x1 x
x y1 y2...............x2 x1
如果x1 能吃x, 那么,x就会选择不吃,让自己不成为最弱的 吃的情况:满足性质1,性质2通过讨论之后发现能吃
如果x1 不吃x,那么,x就会选择吃,多吃一个是一个
不吃的情况:吃了自己就要死,性质2通过讨论之后发现不能吃
递归实现性质2:
判断下一条最强的蛇是否会吃最弱的蛇。
f(cnt): 表示剩余cnt条蛇时,最强的蛇是否会吃最弱的蛇。
if cnt == 1: 不吃
if cnt == 2: 吃
if 最强的蛇吃完最弱的蛇后,满足性质1,则会吃
if 最强的蛇吃完最弱的蛇后,会变成最弱的蛇(满足性质2):
if f(cnt - 1) == true,则选择不吃
else 吃
最后的问题是,如何线性的模拟整个决斗的过程。
两个队列维护
1.原数组从小到大是有序的
2.吃完之后的数组从大到小有序的
类似于归并的合并的两个数组去找最强和最弱的蛇即可。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 20, INF = 2e9;
int n;
int w[N];
struct Snake {
int v, id; //实力和编号
bool operator > (const Snake& T) const { //这样就可以直接比较了
if(v != T.v) return v > T.v;
return id > T.id;
}
bool operator == (const Snake& T) const {
return v == T.v && id == T.id;
}
}q1[N], q2[N];
int hh1, hh2, tt1, tt2;
Snake get_max() //从两个队列中取出,并删除最大值
{
Snake res = {-1, -1};
if(hh1 <= tt1) res = q1[tt1]; //假设最大的是第一个队列的最大值
if(hh2 <= tt2 && q2[tt2] > res) res = q2[tt2]; //用第二个队列更新最大值
if(hh1 <= tt1 && res == q1[tt1]) tt1 --;//如果最大值是在第一个队列tt1--
else tt2 --;//否则tt2--
return res;
}
Snake get_min(bool del = true) {//从两个队列中取出,并删除最小值,参数为false,则只是找最小值
Snake res = {INF, INF};
if(hh1 <= tt1) res = q1[hh1];
if(hh2 <= tt2 && res > q2[hh2]) res = q2[hh2];
if(del){
if(hh1 <= tt1 && res == q1[hh1]) hh1 ++;
else hh2 ++;
}
return res;
}
bool check(int cnt) //判断当前最强的蛇是否会吃最弱的蛇
{
if(cnt == 1) return false;
if(cnt == 2) return true;
Snake strong = get_max(), weak = get_min();
strong.v -= weak.v;
if(strong > get_min(false)) //满足性质1
return true;
q2[ --hh2] = strong;
return !check(cnt - 1); //下一条蛇吃,我就不吃,下一条蛇不吃,我就吃
}
int solve()
{
hh1 = 0, tt1 = -1, hh2 = n, tt2 = n - 1;
for(int i = 1; i <= n; i++)
q1[++tt1] = {w[i], i};
int res = n;
for(int i = 0; i < n - 1; i++) {
Snake strong = get_max(), weak = get_min();
//拿到最强的蛇和最弱的蛇,并删除两条蛇
strong.v -= weak.v;
res --;
q2[ --hh2] = strong; //倒着存进队列2
if(strong == get_min(false)) break; //如果最强的蛇变成的最弱,就停止吃
}
//如果下一条最强的蛇会吃掉最弱的蛇,则返回一步
if(check(res)) res ++;
return res;
}
int main()
{
int t;
cin >> t;
for(int cases = 1; cases <= t; cases ++)
{
if(cases == 1) {
cin >> n;
for(int i = 1; i <= n; i++)
cin >> w[i];
}
else {
int m;
cin >> m;
while(m --) {
int x, y;
cin >> x >> y;
w[x] = y;
}
}
cout << solve() << endl;
}
return 0;
}
0 条评论
目前还没有评论...