[数学记录]AT2164 [AGC006C] Rabbit Exercise

command_block

2021-04-22 10:09:25

Personal

**题意** : 数轴上有 $n$ 只兔子,编号为 $1\sim n$ ,第 $i$ 只兔子的初始坐标为 $x_i$。 兔子会以以下的方式在数轴上行动 :一轮包含 $m$ 次跳跃,第 $j$ 次跳跃中,是兔子 $a_j$ 从兔子 $a_j-1$ 和兔子 $a_j+1$ 中等概率的选一个。 (保证 $2\leq a_j\leq n-1$) 记选的兔子坐标为 $x$ ,那么 $a_j$ 号兔子会跳到它当前坐标关于 $x$ 的对称点。 (注意,即使兔子的位置顺序变化了,但是编号仍保持不变) 兔子会进行 $k$ 轮跳跃,对每个兔子,求出它最后坐标的期望值。以实数的形式输出。 $n,m\leq 10^5,k\leq 10^{18}$。 ------------ 点 $x_0$ 关于 $x_1$ 的对称点为 $2x_1-x_0$ ,这是线性的,所以可以直接维护期望。 现在问题变为,每次给定 $p$ 令 $x_{p}'=x_{p+1}+x_{p-1}-x_p$ ,求将这组 $m$ 个操作重复 $k$ 轮,最终得到的 $x$ 数组。 (不难发现答案其实一定是整数) 这里有三项,较为复杂。考虑差分,记 $d_i=x_i-x_{i-1}$。 则每次操作后 $\begin{cases}d_p'=(x_{p+1}+x_{p-1}-x_p)-x_{p-1}=x_{p+1}-x_p=d_{p+1}\\ d_{p+1}'=x_{p+1}-(x_{p+1}+x_{p-1}-x_p)=x_p-x_{p-1}=d_p\end{cases}$ 实际上相当于交换了 $d_p$ 与 $d_{p+1}$。 记录这些交换构成的映射,接下来就是计算映射的 $k$ 次复合,容易做到 $O(n\log k)$。 注意答案可能爆 `int`。 ```cpp #include<algorithm> #include<cstdio> #define ll long long #define MaxN 100500 using namespace std; int buf[MaxN],sav[MaxN]; void pow(int *a,int n,ll t) { for (int i=1;i<=n;i++){buf[i]=a[i];a[i]=i;} while(t){ if (t&1)for (int i=1;i<=n;i++)a[i]=buf[a[i]]; for (int i=1;i<=n;i++)sav[i]=buf[i]; for (int i=1;i<=n;i++)buf[i]=sav[buf[i]]; t>>=1; } } int n,m,p[MaxN]; ll x[MaxN],ans[MaxN],k; int main() { scanf("%d",&n); for (int i=1;i<=n;i++)scanf("%lld",&x[i]); for (int i=n;i;i--)x[i]-=x[i-1]; scanf("%d%lld",&m,&k); for (int i=1;i<=n;i++)p[i]=i; for (int i=1,j;i<=m;i++){ scanf("%d",&j); swap(p[j],p[j+1]); } pow(p,n,k); for (int i=1;i<=n;i++){ ans[i]=ans[i-1]+x[p[i]]; printf("%lld\n",ans[i]); }return 0; } ```