题意:
给一个长度为n的置换和一个整数q表示询问次数。
每次询问输入一个i和k,表示询问ai在k次操作后的胜场数
每次操作,将序列前两个比较,较大的放在序列前,较小的放在序列末尾
思路:
不难发现,虽然理论上无数次,但是除了最大值,其余所有值都是有限次胜场数目。
一个值的胜场数取决于他前面的最大值是多少,以及他后面,直到k次结束,有多少个比他小的在后面。
可以做一个预处理,记录每一个数,在极限状态下(无限次k)(不包括最大值),最多能胜几次,以及胜场右边界(不难发现一个数如果胜,胜场所有数必为一段连续区间)
剩下的实在不怎么好说,看代码
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int inf = 1e9 + 9;
const ll INF = 1e18l;
/*
priority_queue<int> big_heep;
priority_queue<int,vector<int>,greater<int> > small_heep;
struct cmp{//if return true,it means that the number in the left was smaller than the right one
bool operator () (int a,int b){
}
};
*/
ll a[200005];
ll t[200005];
ll d[200005];
void work() {
ll n, q;
cin >> n >> q;
memset(t, 0, sizeof(int) * (n + 3));
memset(d, 0, sizeof(int) * (n + 3));
for (int i = 1;i <= n;i++) cin >> a[i];
ll maxa = 0;
ll maxid = 0;
for (int i = 1;i <= n;i++) {
if (a[i] > maxa) {
maxa = a[i];
maxid = i;
}
}
ll last = 0;
ll lastid = 0;
for (int i = 1;i <= n;i++) {
if (i == 1) {
if (a[i] > a[i + 1]) {
last = a[i];
lastid = i;
t[i]++;
d[i] = i;
t[i + 1] = 0;
}
else {
last = a[i + 1];
lastid = i + 1;
t[i + 1]++;
d[i + 1] = i + 1;
t[i] = 0;
}
i++;
}
else {
if (last > a[i]) {
t[lastid]++;
d[lastid] = i;
t[i] = 0;
}
else {
last = a[i];
lastid = i;
t[i] = 1;
d[i] = i;
}
}
}
for (int p = 1;p <= q;p++) {
ll x, k;
cin >> x >> k;
if (t[x] == 0) {
cout << 0 << "\n";
continue;
}
else {
if (maxid == x) {
if (k + 1 <= n) {
ll len = x-k-1;
if (len <= 0) {
if (k + 1 > d[x]) cout << t[x] << "\n";
else cout << t[x] - (d[x] - k-1) << "\n";
}
else cout << 0 << "\n";
}
else {
int kk = k - (n - 1);
cout << t[x] + kk << "\n";
}
}
else {
ll len = x - k - 1;
if (len <= 0) {
if (k + 1 > d[x]) cout << t[x] << "\n";
else cout << t[x] - (d[x] - k-1) << "\n";
}
else cout << 0 << "\n";
}
}
}
return;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
ll t;
cin >> t;
while (t--) {
work();
}
return 0;
}