【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;
posted @ 2021-02-20 12:25  Jayun  阅读(73)  评论(0编辑  收藏  举报