codeforces 1288E. Messenger Simulator

传送门

题意

给你一个长度为n序列,初始时为 1 , 2 , 3 , . . . , n 1,2,3,...,n ,有m次操作,每次操作把一个数字放在序列的最前方,求出每一个数字的下标在操作过程中的最小值 m i n n [ x ] minn[x] 和最大值 m a x n [ x ] maxn[x]

题解

  • 模拟不太可行
  • 当要操作数字x时,此时x所在的位置可能就是最大值的答案,因此如果x要被操作时:
    • m i n n [ x ] = 1 minn[x]=1
    • m a x n [ x ] = m a x ( m a x n [ x ] , s u m [ p o s [ x ] ] ) , p o s [ x ] maxn[x]=max(maxn[x],sum[pos[x]]),pos[x] x此时的位置, s u m [ p o s [ x ] ] sum[pos[x]] x所在位置之前的数的个数,用BIT维护
    • 因为有m个数需要提前,所以将初始序列之前空出m个空用来插入,这样方便维护,具体看代码
  • 当所有操作结束时仍需要把最大值更新一遍

C++

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1e6 + 500;

int n, m, c[N], maxn[N], minn[N], pos[N];

int lowbit(int x)
{
    return x & -x;
}

void add(int x, int y)
{
    for (int i = x; i < N; i += lowbit(i))
        c[i] += y;
}

int sum(int x)
{
    int tot = 0;
    for (int i = x; i; i -= lowbit(i))
        tot += c[i];
    return tot;
}

int main()
{
    //freopen("r.txt", "r", stdin);
    ios::sync_with_stdio(false);
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        maxn[i] = minn[i] = i;
        pos[i] = i + m;
        add(pos[i], 1);
    }
    for (int x, i = m; i; i--)
    {
        cin >> x;
        minn[x] = 1;
        maxn[x] = max(maxn[x], sum(pos[x]));
        add(pos[x], -1);
        pos[x] = i;
        add(pos[x], 1);
    }
    for (int i = 1; i <= n; i++)
        maxn[i] = max(maxn[i], sum(pos[i]));

    for (int i = 1; i <= n; i++)
        cout << minn[i] << " " << maxn[i] << endl;
}
发布了7 篇原创文章 · 获赞 1 · 访问量 125

猜你喜欢

转载自blog.csdn.net/qq_36552779/article/details/104044174