Loading

C. Fighting Tournament(模拟 分类讨论) CF1719C

题目:

​ 有一个长度为n的战斗序列,每次取序列的前两个人PK,能力值高者获胜,留在第一位,败者会被放到序列的最后一位。有q次询问,战斗了k轮后第i个人的胜利次数。

分析:

​ 能力最高的人到序列的第二位的时候,其他人将不可能再胜利了,将这个轮数记为round,round轮之后就被固定了。那么我们只需要预处理出每个人在round内的胜利场次,再分类讨论一下就可以了。

实现:

​ 如果\(k>=round\)的话,那么可以通过双端队列模拟得到i赢的场次。

​ 但是如果我们需要知道\(k < round\)的时候,每个人的胜利场次的话,对于每个\(i\),我们需要知道他左边和右边第一个比他大的人的下标,这样就可以推出他赢的场次。

​ 可以用\(l[i], r[i]\)来表示左边的第一个大于\(i\)的人的下标,和右边的第一个大于i的人的下标。如果左边有一个大于i的人或者k轮也无法到达第二,那么\(i\)将一场不赢。否则i进入第二的时候,可以赢一把,再加上\(min(k,r[i] - i - 1)\),就是胜利场次了。

#include <bits/stdc++.h>
    
using namespace std;
#define rep(i, a, n) for(int i = a; i < n; i++)
#define all(x) x.begin(), x.end()
#define pb push_back
#define ios ios::sync_with_stdio(false);cin.tie(0);
#define debug(x)    cout << x << endl;
#define SZ(x)    (int)x.size()
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
const int inf = 0x3f3f3f3f;
void read(int &x) {int s = 0, f = 1; char ch = getchar(); while(!isdigit(ch)) {f = (ch == '-' ? -1 : f); ch = getchar();} while(isdigit(ch)) {s = s * 10 + ch - '0'; ch = getchar();} x = s * f;}

const int N = 200005;
int n, _round, m;
deque<int> dq; //双端队列模拟
int a[N], mp[N]; //a是能力值 mp是从值映射回到下标
int num[N]; //到达_round的时候,i赢了多少场
int l[N], r[N];

void init()
{   
    _round = 0;
    while(1)
    {
        if(dq[0] == n)
            break;
        if(dq[0] > dq[1])
            swap(dq[0], dq[1]);
        _round ++;
        num[mp[dq[1]]] ++;
        int tmp = dq[0];
        dq.pop_front();
        dq.push_back(tmp);
    }

    int pos = 0;
    for(int i = 1; i < n; i ++)
        if(a[pos] > a[i])
            l[i] = pos;
        else
            r[pos] = i, pos = i;
}

int calc(int pos, int k)
{
    int res = 0;
    
    if(l[pos] != -1) //左边存在任意一个权值大于a[pos]的,一场不能赢
        return 0;
    
    if(k >= _round)
    {
        res = num[pos];
        if(a[pos] == n)
            res += k - _round;
        return res;
    }
    
    k -= pos;
    if(k < 0)   return 0;
    return min(k, r[pos] - pos - 1) + (pos != 0); //赢前面的一个人
}

void init1(int len)
{
    dq.clear();
    memset(mp, 0, sizeof mp);
    rep(i, 0, len)    
        num[i] = 0, l[i] = -1, r[i] = n;
}

void solve()
{
    cin >> n >> m;
    init1(n);
    rep(i, 0, n)
    {
        cin >> a[i];
        mp[a[i]] = i;
        dq.push_back(a[i]);
    }

    init();

    while(m --)
    {
        int pos, k; cin >> pos >> k;
        -- pos;
        cout << calc(pos, k) << '\n';
    }
}

signed main()
{
    ios;
    int _ = 1;
    cin >> _;
    while(_--)
        solve();
}
posted @ 2022-09-01 09:14  DM11  阅读(43)  评论(0编辑  收藏  举报