这个题,看了题解之后大家都是用到了一个数学结论,emmm我一开始补题并没有想到这个结论,我想给大家说一下如果用栈怎么做(题解里看到有大佬说用栈做的),这里详细展开一下:
#include <bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
int t;
cin >> t;
while (t--) // 最贪心的选择是尽早选
{
int n;
cin >> n;
stack<pair<int, int>> q;
vector<int> a(n + 2, 0);
a[n + 1] = -1;
vector<int> ans(n + 2, 0);
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
q.push({a[1], 1});
for (int i = 2; i <= n; i++)
{
if (!q.empty() && q.top().first == a[i] && a[i + 1] != a[i])
{
while (!q.empty() && q.top().first == a[i])
{
q.pop();
}
}
else
{
if (!q.empty() && a[i] < q.top().first)
{
ans[i] = a[i];
while (!q.empty() && q.top().first > a[i])
{
auto [zhi, id] = q.top();
ans[id] = zhi;
q.pop();
}
if (!q.empty() && a[i] != a[i + 1] && q.top().first == a[i])
{
while (!q.empty() && a[i] != a[i + 1] && q.top().first == a[i])
{
q.pop();
}
}
else
{
q.push({a[i], i});
continue;
}
}
else
{
q.push({a[i], i});
}
}
}
while (!q.empty())
{
auto [zhi, id] = q.top();
q.pop();
ans[id] = zhi;
}
for (int i = 1; i <= n; i++)
{
if (ans[i] != 0)
{
if (a[i - 1] > a[i]&&ans[i-1]==0)
{
ans[i] = 0;
}
}
}
for (int i = n; i >=1; i--)
{
if (ans[i] != 0)
{
if (a[i + 1] > a[i]&&ans[i+1]==0)
{
ans[i] = 0;
}
}
}
int tai = 1;
for (int i = 1; i <= n; i++)
{
if (ans[i] != 0)
{
tai = 0;
break;
}
}
if (!tai)
cout << "No" << '\n';
else
{
cout << "Yes" << '\n';
}
}
}
乍一看,很长其实给我的感觉就像开心消消乐一样,只不过这个开心消消乐是用栈实现的,题目里说如果遇到区间的左右端点是相同的,且区间内的元素大于端点那么就可以减去1,但其实我们可以一直操作到端点为0为止,所以我们就有了压栈的操作,但是必须要注意的是如果一旦有某个元素设为x,是小于顶元素的那么就是不能相消的,即顶元素是不能通过相消来实现的,所以一直弹出一直弹到顶元素是小于等于x,那么这时可以再次执行相消操作。
最后的ans其实在还原这样一个事情 3 3 2 当3 3 减到2的时候其实是可以把第三个元素2一起消到0的,也就是说是有解的,所以我们检查到某个元素可以化为0的话,我们看他一开始的元素值和他相邻的不能化为0的元素值大小,如果不能化为0的元素值小于可以化为0的值那么他也可以被化为0。贪心推平确实如此

京公网安备 11010502036488号