Fzuoj 2260 Card Game【单调栈+Dp】

本文介绍了一种通过模拟单调栈解决卡牌游戏问题的方法。该方法可以高效地计算出游戏中取牌所需的总轮次及最终剩余卡牌序列,适用于算法竞赛等场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 Problem 2260 Card Game

Accept: 82    Submit: 380
Time Limit: 3000 mSec    Memory Limit : 32768 KB

 Problem Description

有如下取牌游戏:

1. 桌面上有n张卡牌从左到右排成一行,每张卡牌上有一个数字;

2. 游戏按轮次进行,每一轮中取掉所有比左边数值小的卡牌;

3. 当无牌可取的时候则游戏结束。

比如初始卡牌为{5, 6, 3, 7, 4, 1, 2},共需2轮取牌。取牌过程如下(小括号为每轮取掉的牌):

{5, 6, 3, 7, 4, 1, 2}

==> {5, 6, (3), 7, (4), (1), 2}

==> {5, 6, 7, 2}

==> {5, 6, 7, (2)}

==> {5, 6, 7}

现按顺序给定初始的卡牌数字,请求出游戏结束时取牌的总轮次,并输出结束时桌上剩余的卡牌序列。

 Input

包含多组测试数据。

输入包含两行。

第一行包含一个整数n表示卡牌的数量。

第二行包含n个空格隔开的整数,表示排成一行的卡牌上对应的数字(取值范围[1,1000000000])。

n≤1000000

 Output

输出包含两行。

第一行包含一个整数表示游戏的取牌总轮次。

第二行包含游戏结束时桌上剩余的卡牌序列,用空格隔开。

 Sample Input

7
5 6 3 7 4 1 2

 Sample Output

2
5 6 7

 Source

福州大学第十四届程序设计竞赛_重现赛

思路:


我们模拟一下单调栈就能理解了。对于样例的解释:

①首先将5放入栈,设定其价值为0.表示这个点现在左边没有比他大的点,也就是这个点不需要操作。

②然后将6放入栈,同时需要先将5弹出栈,现在栈内情况为:(6)同时设定其价值为0.

③然后将3放放入栈,现在栈内情况为:(6,3),此时我们设定3的价值为0+1.

④然后将7放入栈,同时弹出3和6,设定7的价值为0,现在栈内的情况为:(7);

⑤然后将4放入栈,现在栈内情况为:(7,4),我们此时设定4的价值为0+1.

⑥然后将1放入栈,现在栈内情况为:(7,4,1),我们此时设定1的价值为1+1=2.

⑦最后将2放入栈,同时弹出1,现在栈内情况为:(7,4,2),我们此时设定2的价值为1+1=2.


价值最大为2,所以整体需要2次操作。

所以我们每次操作的时候,先将栈内老元素弹出,同时维护弹出的元素的最大价值(maxn),那么我们此时再加入栈内的元素的价值就是这个最大价值+1(maxn+1),表示我们这个当前数字操作的次数是要接着之前几个数进行的。如果没有弹出操作,那么对应maxn就是0.

过程维护一下即可。

具体内容参考代码。


Ac代码:

#include<stdio.h>
#include<string.h>
#include<queue>
#include<stack>
using namespace std;
struct node
{
    int val,num;
}now,nex;
int a[1050000];
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        int ans=0;
        stack<node>s;
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)
        {
            int sum=0;
            while(!s.empty())
            {
                now=s.top();
                if(now.num<a[i])
                {
                    s.pop();
                    sum=max(sum,now.val);
                }
                else break;
            }
            nex.val=sum+1;
            nex.num=a[i];
            if(s.size()==0)nex.val=0;
            ans=max(ans,nex.val);
            s.push(nex);
        }
        printf("%d\n",ans);
        int pre=a[1];
        printf("%d",a[1]);
        for(int i=2;i<=n;i++)
        {
            if(a[i]>=pre)
            {
                printf(" %d",a[i]);
                pre=a[i];
            }
        }
        printf("\n");
    }
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值