AT2164-[AGC006C]Rabbit Exercise【差分,倍增,数学期望】

正题

题目链接:https://www.luogu.com.cn/problem/AT2164


题目大意

\(n\)只兔子编号为\(1\sim n\),第\(i\)只在坐标轴\(x_i\)处。然后\(m\)次跳跃,每次给出\(a_i\),编号为\(a_i\)的兔子会等概率的选取\(a_{i-1}\)\(a_{i+1}\)跳跃到对称位置。进行\(k\)轮,求最后每只兔子的期望位置。

\(3\leq n\leq 10^5,1\leq m\leq 10^5,1\leq k\leq 10^{18}\)


解题思路

\(f_i\)表示\(i\)的期望位置的话,对于每次跳跃兔子\(x\),它的概率就是

\[f_x=\frac{(2f_{x-1}-f_{x})+(2f_{x+1}-f_x)}{2}=f_{x-1}+f_{x+1}-f_{x} \]

然后这个见到这个式子就直接差分成\(g_i=f_i-f_{i-1}\)

然后上面那个东西就变成了交换\(i\)\(i+1\)

然后就是给一个交换,交换\(k\)次,因为\(k\)很大倍增搞就好了。

时间复杂度\(O(n\log k)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=1e5+10;
ll n,m,k,d[N],ans[N],t[N];
double x[N];
signed main()
{
	scanf("%lld",&n);
	for(ll i=1;i<=n;i++){
		scanf("%lf",&x[i]);
		d[i]=ans[i]=i;
	}
	scanf("%lld%lld",&m,&k);
	for(ll i=1;i<=m;i++){
		ll x;scanf("%lld",&x);
		swap(d[x],d[x+1]);
	}
	while(k){
		if(k&1){
			for(ll i=1;i<=n;i++)t[i]=ans[d[i]];
			for(ll i=1;i<=n;i++)ans[i]=t[i];
		}
		for(ll i=1;i<=n;i++)t[i]=d[d[i]];
		for(ll i=1;i<=n;i++)d[i]=t[i];
		k>>=1;
	}
	double sum=0;
	for(ll i=1;i<=n;i++){
		sum+=x[ans[i]]-x[ans[i]-1];
		printf("%.1lf\n",sum);
	}
	return 0;
}
posted @ 2021-03-04 21:13  QuantAsk  阅读(46)  评论(0编辑  收藏  举报