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();
}