1 条题解

  • 1
    @ 2024-6-6 17:14:12

    【题目大意】接竹竿游戏规则为按顺序依次加入一个牌堆,如果发现牌堆中有一对相同的牌,则将两张牌中间的牌(包含两张牌)全部拿出,求最终牌堆有多少牌。

    有一个序列 aa,有 qq 次询问,每次询问给出 l,rl,r,求出 [l,r][l,r] 的接竹竿结果。

    【考纲知识点】倍增,RMQ

    【解题思路】根据题意,每张牌最大的数字是13,然后根据提供的区间L,R【L,R】,看长度最远的2个数字,去掉后剩下的卡牌数量。注意:按照队列方式入队,遇到相同的数字,之间的卡牌数字就全部消失。例如,1,2,3,1,4,2,3。消失的是1231,而不是23142这个区间。另一种情况,如果是3个1,例如1,2,1,3,1,4,2,会消除121这3张卡牌。

    结论:记录下一个出现的数字;求该区间内,第一个和它相同的数字。用区间最值来求。

    从左到右去查找,如果第1个数字,队列后面没有相同的,继续判断第2个。

    求解:区间是[L,R],和第1个数字相同的最近数字的位置,该位置不能超过R。依次类推求第2个,第3个……。

    可以用区间最值RMQ来统计。注意要倒序处理,从n到1;

    【参考程序】

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long 
    const int N = 1e5 + 10;
    int a[N];
    int nxt[N][30], pos[20];
    int main()
    {
        int t;
        cin >> t;
        while (t--)
        {
            int n;
            cin >> n;
            memset(pos, 0, sizeof pos);
            for (int i = 1; i <= n; i++)
            {
                cin >> a[i];
                for (int j = 0; j <= 20; j++)
                    nxt[i][j] = n + 1;
            }
            for (int i = n; i >= 1; i--)
            {
                if (!pos[a[i]])
                {
                    nxt[a[i]][0] = n + 1;
                    pos[a[i]] = i;
                }
                else
                {
                    nxt[i][0] = pos[a[i]];
                    pos[a[i]] = i;
                }
            }
            for (int i = n; i >= 1; i--)
            {
                for (int j = 1; j <= 20; j++)
                {
                    if (nxt[i][j - 1] + 1 <= n)
                        nxt[i][j] = nxt[nxt[i][j - 1] + 1][j - 1];
                }
            }
            int q;
            cin >> q;
            while (q--)
            {
                int l, r;
                cin >> l >> r;
                int ii = l;
                int ans = 0;
                while (ii <= r)
                {
    
                    while (ii <= r && nxt[ii][0] > r)
                    {
                        ii++;
                        ans++;
                    }
                    if (ii > r)
                        break;
                    for (int j = 20; j >= 0; j--)
                    {
                        if (nxt[ii][j] <= r)
                        {
                            ii = nxt[ii][j];
                            break;
                        }
                    }
                    ii++;
                }
                cout << ans << "\n";
            }
        }
    }
    
    • 1

    [GESP202403 八级] 接竹竿

    信息

    ID
    598
    时间
    1000ms
    内存
    512MiB
    难度
    9
    标签
    递交数
    13
    已通过
    3
    上传者