题解:P15576 [USACO26FEB] Good Cyclic Shifts G
感觉题挺牛的。
如果一个排列能够通过至多
首先让我们观察一下
那么和怎么和逆序对扯上关系呢?我们考虑对于任何一个满足
在位置
我们把所有
所以只有取等时才是好的排列哦。
这意味着,对于每一个元素,不能产生任何“多余”的逆序对,这就是一个比较经典的问题了。
假设排列中存在 321 模式,即存在下标
它无非就两种情况:
-
情况一:
p_j \leq j 它对f(p) 的贡献是0 。但j < k 且p_j > p_k ,它和后面的p_k 形成了一个逆序对。这个逆序对在f(p) 里没有被算进去,此时必然inv(p) > f(p) 。 -
情况二:
p_j > j 此时i < j ,且p_i > p_j 。这说明左边混进了一个比它大的数。这就导致右边必然会多出一个比它小的数,从而又产生了一个“额外”的逆序对。必然inv(p) > f(p) 。
那么剩下的问题就简单了,破环成链然后统计下
#include <bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i <= (b); i ++ )
#define repf(i, a, b) for(int i = (a); i >= (b); i -- )
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
const int P = 1e9 + 7;
int a[N << 1]; int lmx[N << 1], rmi[N << 1];
int stk[N<<1], top; int c[N << 1]; int b[N << 1];
int f[18][N << 1], lg[N << 1];
inline int Q(int l, int r)
{
int len = r - l + 1;
return max(f[lg[len]][l], f[lg[len]][r - (1 << lg[len]) + 1] );
}
int main()
{
ios :: sync_with_stdio(0); cin.tie(0); cout.tie(0);
int T; cin >> T;
while(T -- )
{
int n; cin >> n;
rep(i, 1, n) cin >> a[i], a[i + n] = a[i];
int nn = n << 1;
rep(i, 1, nn) b[i] = 0;
stk[0] = -1;
top = 0;
rep(i, 1, nn)
{
while(top && a[stk[top]] < a[i]) top --;
lmx[i] = stk[top];
stk[++ top] = i;
}
top = 0;
repf(i, nn, 1)
{
while(top && a[stk[top]] > a[i]) top --;
rmi[i] = stk[top];
stk[++ top] = i;
}
rep(i, 1, nn) if(lmx[i] != -1 && rmi[i] != -1)
{
b[rmi[i]] = max(b[rmi[i]], lmx[i]);
c[lmx[i]] ++, c[rmi[i] + 1] --;
}
rep(i, 2, nn) lg[i] = lg[i >> 1] + 1;
rep(i, 1, nn) f[0][i] = b[i];
rep(j, 1, 17) rep(i, 1, nn - (1 << j) + 1) f[j][i] = max(f[j - 1][i], f[j - 1][i + (1 << (j - 1))]);
int sm = 0;
rep(i, 1, n) sm += c[i];
vector<int> v;
rep(i, n + 2, nn + 1)
{
if(Q(i - n, i - 1) >= i - n);
else v.push_back(nn - i + 1);
sm += c[i - n], sm += c[i];
}
cout << v.size() << '\n';
reverse(v.begin(), v.end());
for(auto x : v) cout << x << ' ';
cout << '\n';
}
return 0;
}