1 条题解

  • 0
    @ 2024-5-17 18:55:12

    题目大意: q 次询问,每次取卡牌序列的 [L,R] 区间来玩接竹竿会剩下多少张牌 接竹竿规则为:每张牌上有一个点数 v ,将给定的牌依次放入一列牌的末端。若放入之前这列牌中已有与这张牌点数相同的牌,则小核桃会将这张牌和点数相同的牌之间的所有牌全部取出队列(包括这两张牌本身)

    思路

    我们定义从第 x 张牌开始玩,第一次出现 vy = vx 的情况,也就是将 x~y 之间的牌都取出,为 x 的一次跳跃,那么 x 会跳到 y+1 ,即 f[x][0] = y+1 。如果不存在这样的 y ,那么 f[x][0] = x 。记 f[i][j] 为从 i 出发跳 2^j 次的结果。

    第一步,用倍增预处理出 f[i][j] 。

    第二步,在回答询问时,如果 f[x][j] <= r+1 且 f[x][j+1] > r+1 ,那么我们可以确定,从 x 出发的跳跃次数在 2^j~2^(j+1) 之间,所以我们从大到小枚举j,第一次出现 f[x][j] <= r+1 时进行跳跃,然后重新从 f[x][j] 开始下一轮跳跃。

    第三步,如果第二步中连续跳跃的结果是 x <= r,那么本次游戏中第 x 张牌会被留下,答案加一。因为留下的牌一定点数不同,所以最多只会发生 13 次答案加一。

    参考代码
    for (int i = 1; i <= q; ++i)    //处理询问 
        {
            int x = l[i];   //x表示起跳点
            int ans=0;
            while(x <= r[i])
            {
                for (int j = log2n; j >= 0; --j)
                {
                    if(f[x][j] <= r[i] + 1)
                        x = f[x][j];
                }
                if(x <= r[i])
                {
                    ans++;
                    x++;
                }
            }
            cout << ans << endl; 
        }
    
    • 1

    信息

    ID
    739
    时间
    1000ms
    内存
    256MiB
    难度
    6
    标签
    (无)
    递交数
    46
    已通过
    13
    上传者