C. Element Extermination(贪心,模拟,结论)

C. Element Extermination

题意:给出一个数组,相邻两个数字满足 A i < A i − 1 A_i < A_{i-1} Ai<Ai1,就可以删除其中一个数字。问是否存在一种删除方案,使数组中只剩下一个元素。

思路:

栈模拟

用栈来模拟数字在数组中的 先后顺序(先后入栈)和贪心决策(是否入栈,是否出栈)

设要入栈元素a,栈顶元素b
1.如果栈为空,直接入栈。
2.如果 a < b a < b a<b,直接入栈。
3.如果 a > b a > b a>b,就满足删除的条件,到了贪心决策的问题了。
(1).如果此时栈中只有一个元素,我们优先选择较小的 b b b。:
分区间讨论,假如在a的右边有 [ a , n ] [a,n] [a,n]中的元素,那留下 a , b a,b ab都行,假如在 a a a的右边有 [ b , a ] [b,a] [b,a]中的元素,只能留下 b b b,假如在 a a a的右边有 [ 1 , b ] [1,b] [1,b]中的元素,那么留下 a , b a,b ab都不行, b b b的优先级更高。
(2).如果栈中有多个元素,我们要尽量的删除较多的元素。
那我们也可以分区间讨论,栈中元素所在区间,和留下 a , b a,b ab,哪个可能删除的元素更多。讨论结果就是留下 a a a,循环删除栈中的元素,直到栈中只剩下一个元素或不满足删除条件。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5+10;
const int inf = 0x7ffffff;
int f[][2] = {
    
    1, 0, 0, 1, -1, 0, 0, -1}, n, m;
int s[N];
int read() {
    
    
    int x = 0; int f = 1; char s = getchar();
    while(s < '0' || s > '9') {
    
    if(s == '-') f = -1; s = getchar();}
    while(s >= '0' && s <= '9') {
    
    x = (x << 3) + (x << 1) + s - 48; s = getchar();}
    return x * f;
}
int main() {
    
    
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    int t;
    t = read();
    while(t--) {
    
    
        stack<int> T;
        int n, f, mx = 0, mi = 0;
        n = read();
        for(int i=1; i<=n; i++) {
    
    
            s[i] = read();
            if(s[i] == 1) f = i;
        }
        for(int i=1; i<=n; i++) {
    
    //一个一个元素进行决策。
            if(T.empty()) T.push(s[i]);//空
            else if(s[i] < T.top()) T.push(s[i]);//不满足删除条件
            else {
    
    //满足删除条件
                if(T.size() == 1) continue;//只有一个元素
                else T.push(s[i]);
                while(1) {
    
    //贪心决策
                    int a = T.top(); T.pop();
                    int b = T.top(); T.pop();
                    if(a > b) {
    
    //留a还是留b
                        if(T.size() > 0) T.push(a);
                        else T.push(b);
                    }
                    else {
    
    //不满足删除条件了
                        T.push(b); T.push(a);
                        break;
                    }
                    if(T.size() == 1) break;//只剩下一个元素
                }
            }
        }
        if(T.size() == 1) puts("YES");
        else puts("NO");
    }
    return 0;
}

按照上面的模拟,我们可以想想第一个元素是不是一直没有被删除。在对最后一个元素进行决策时,如果最后一个元素会和第一个元素相遇,且满足删除条件的话( A 1 < A n A_1 < A_n A1<An),就会留下第一个元素。如果在中间的时候就存在不满足删除条件的情况,我们按这样排一下序。
第 一 个 元 素 A 1 , 对 最 后 一 个 元 素 不 满 足 删 除 条 件 的 元 素 A i , 最 后 一 个 元 素 A n 第一个元素A_1,对最后一个元素不满足删除条件的元素A_i,最后一个元素A_n A1AiAn
可以推出 A i > A n A_i > A_n Ai>An,且因为在对 A i A_i Ai这个元素决策的时候,留下了它,说明 A 1 > A i A_1 > A_i A1>Ai。这里已经有结论的影子了,具体证明我也弄不出来。

结论

只需要比较第一和最后一个数字的大小即可。
S 1 > S n ,     N o             S 1 < S n ,     Y E S S_1 > S_n,~~~No~~~~~~~~~~~S_1 < S_n,~~~YES S1>Sn,   No           S1<Sn,   YES

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5+10;
const int inf = 0x7ffffff;
int f[][2] = {
    
    1, 0, 0, 1, -1, 0, 0, -1}, n, m;
int s[N];
int read() {
    
    
    int x = 0; int f = 1; char s = getchar();
    while(s < '0' || s > '9') {
    
    if(s == '-') f = -1; s = getchar();}
    while(s >= '0' && s <= '9') {
    
    x = (x << 3) + (x << 1) + s - 48; s = getchar();}
    return x * f;
}
int main() {
    
    
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    int t;
    t = read();
    while(t--) {
    
    
        int n, f, mx = 0, mi = 0;
        n = read();
        for(int i=1; i<=n; i++) {
    
    
            s[i] = read();
        }
        if(s[n] < s[1]) printf("NO\n");
        else printf("YES\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45363113/article/details/107250935