正题
题目链接: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;
}