zoukankan      html  css  js  c++  java
  • [Codeforces 1236E]Alice and the Unfair Game

    Description

    题库链接

    (n) 个盒子和 (m) 次操作,第 (i) 次操作 Alice 会询问第 (a_i) 个盒子里是否有小球。为了避免 Alice 获得胜利,Marisa 会在每一次操作之前可以将藏着小球的盒子移到相邻的盒子,在 (m) 次询问后也可以进行移动。

    ((x,y)) 表示一开始 Marisa 将小球放在 (x) 号盒子,最终小球在 (y) 号盒子的一次游戏。询问所有使得 Marisa 获得胜利的 ((x,y)) 的有序对个数。

    (1 leq n,m leq 10^5)

    Solution

    可以证明对于一个起点,其最终能到达的终点一定是一个连续的区间。那么我们只需要对于每一个起点,找到其最终的左右端点即可。

    以右端点为例,需要找到最右的点的话就需要他要尽可能向右移动。但是如果向右移动会在下一轮受到阻碍的话,他就应该在原地停留一回合。停留一回合之后,他之后的走法完全和他左边这一个格子向下走一样。因此只需要求出左边这个格子能到达的最右是多少就行。

    (R_i) 表示第 (i) 个位置为起点,一直向右走,碰到的石子个数。显然最右端点为 (i+m+1-R_i)

    考虑如何计算这个 (R)。我们逆着做,这样初值均为 0。当第 (a_i) 个盒子有阻碍时,也就是从第 (a_i-i) 个位置作为起点过来的受到看阻碍,因此 (R_{a_i-i}=R_{a_i-i-1}+1)

    注意逆推是不用考虑前面的阻碍对他的影响的。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 3e5+5, X = 1e5;
    
    int n, m, a[N], L[N], R[N];
    
    int main() {
        scanf("%d%d", &n, &m);
        if (n == 1) return puts("0"), 0;
        for (int i = 1; i <= m; i++)
            scanf("%d", &a[i]);
        for (int i = m; i >= 1; i--) {
            R[X+a[i]-i] = R[X+a[i]-i-1]+1;
            L[X+a[i]+i] = L[X+a[i]+i+1]+1;
        }
        long long ans = 0;
        for (int i = 1; i <= n; i++)
            ans += min(n, i+m+1-R[i+X])-max(1, i-(m+1)+L[i+X])+1;
        printf("%I64d
    ", ans);
        return 0;
    }
  • 相关阅读:
    【scala语言入门】二、匿名函数
    【scala语言入门】 一、apply与unapply
    关于timeOut超时后是否会回滚的思考
    [算法]-插入排序
    【oenCV系列】 写视频
    【Opencv系列】
    Factory Method模式精解(C++版本)
    Template Method模式精解(C++版本)
    Adapter模式精解(C++版本)
    迭代器模式精解(C++版本)
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/12937473.html
Copyright © 2011-2022 走看看