【Luogu P4375】[USACO18OPEN]Out of Sorts G
链接:
题目大意:
有一段代码:
sorted = false
while (not sorted):
sorted = true
moo
for i = 0 to N-2:
if A[i+1] < A[i]:
swap A[i], A[i+1]
for i = N-2 downto 0:
if A[i+1] < A[i]:
swap A[i], A[i+1]
for i = 0 to N-2:
if A[i+1] < A[i]:
sorted = false
让你求这段代码里的 moo
会运行多少次。
正文:
这道题的思路很妙。首先单独看第一个 for
循环,你会发现这个操作其实等价于将若干个数 \(a_i\) 移到一个第一个大于它的数的前面,第二个循环类似。设 \(x\) 表示一个中心点,要求两个循环的若干个数中分别至少有一个数在移动的时候经过 \(x\)。我们不妨把每次 moo
都是第一个循环的那个数和第二个循环的那个数互相搭配。
如果要让 moo
的次数多,那么就意味着让 \(x\) 前后更多数相搭配。归纳一下,我们给 \(a\) 数组离散化得到排名数组 \(r\),那么相搭配必定是 \(x\) 前的数的排名要大于 \(x\),\(x\) 后的数相反。答案即:
\[\max_{x=1}^{n}\{(\sum_{i\leq x,r_i>x}1)\}
\]
然后就可以树状数组维护了。
代码:
const int N = 1e5 + 10;
int n;
struct node
{
int id, val;
}a[N];
int t[N], ans = 1;
void modify(int x){for (; x <= n; x += x & -x) t[x]++;}
int query(int x){int ans = 0;for (; x; x -= x & -x) ans += t[x]; return ans;}
bool cmp(node a, node b){return a.val < b.val;}
bool cmp2(node a, node b){return a.id < b.id;}
int main()
{
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
scanf ("%d", &n);
for (int i = 1; i <= n; i++)
scanf ("%d", &a[i].val), a[i].id = i;
sort (a + 1, a + 1 + n, cmp);
for (int i = 1; i <= n; i++) a[i].val = i;
sort (a + 1, a + 1 + n, cmp2);
for (int i = 1; i <= n; i++)
{
modify(a[i].val);
ans = max(ans, i - query(i));
}
printf ("%d\n", ans);
return 0;