[洛谷] AT2164 [AGC006C] Rabbit Exercise

Description

\(Link\)

Solution

一道好题,涉及到差分化简以及倍增求置换。

注意到一次操作后,\(a[i]\)的位置期望为\(E(a[i])=\frac{1}{2}(E(2a[i+1]-a[i])+E(2a[i-1]-a[i]))=E(a[i+1]+a[i-1]-a[i])\)

这么看不太好求。但对\(a\)差分后,发现一次这样的操作就是对差分数组\(d\)进行\(swap(d[i],d[i+1])\)

那么就是对\(d\)进行\(k\)轮置换。注意到\(k\)很大,可以通过倍增优化,和快速幂类似。

即我们记录两个数组\(p\)\(q\)\(p\)保存置换一轮后的结果,相当于快速幂的\(base\)。而\(q\)保存答案即可。

Code

#include <bits/stdc++.h>

using namespace std;

#define ll long long

int n, m, x[100005], p[100005], q[100005], a[100005], cnt[100005];

ll sum, k;

int read()
{
	int x = 0, fl = 1; char ch = getchar();
	while (ch < '0' || ch > '9') { if (ch == '-') fl = -1; ch = getchar();}
	while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + ch - '0'; ch = getchar();}
	return x * fl;
}

int main()
{
	n = read();
	for (int i = 1; i <= n; i ++ )
	{
		x[i] = read();
		p[i] = q[i] = i;
	}
	m = read(); scanf("%lld", &k);
	for (int i = 1; i <= m; i ++ )
	{
		a[i] = read();
		swap(p[a[i]], p[a[i] + 1]);
	}
	while (k)
	{
//		printf("%lld\n", k);
		if (k & 1ll)
		{
			for (int i = 1; i <= n; i ++ )
				cnt[i] = q[p[i]];
			for (int i = 1; i <= n; i ++ )
				q[i] = cnt[i];
		}
		for (int i = 1; i <= n; i ++ )
			cnt[i] = p[p[i]];
		for (int i = 1; i <= n; i ++ )
			p[i] = cnt[i];
		k >>= 1ll;
	}
	for (int i = 1; i <= n; i ++ )
	{
		sum += (ll)(x[q[i]] - x[q[i] - 1]);
		printf("%.1lf\n", (double)(sum));
	}
	return 0;
}
posted @ 2021-02-23 14:36  andysj  阅读(41)  评论(1编辑  收藏  举报