AGC600 C Rabbit Exercise —— 置换
题目:https://agc006.contest.atcoder.jp/tasks/agc006_c
考虑 \( i \) 号兔子移动后位置的期望,是 \( x_{i+1} + x_{i-1} - x_{i} \)
然后作差分,发现按顺序移动一次,实际上是交换了 \( d_{a_{i}} \) 和 \( d_{a_{i}+1} \)
于是可以先处理出移动一次的置换,然后快速幂;
而这是 \( nlogn \) 的做法,还可以找循环来做到 \( O(n) \) ,可见 Narh 的博客;
就写了 \( nlogn \) 的做法。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; typedef double db; int const xn=1e5+5; int n,m,a[xn],t[xn],p[xn]; db d[xn],tt[xn]; ll k; ll rd() { ll ret=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return f?ret:-ret; } void pw() { memcpy(t,p,sizeof t); for(int i=1;i<=n;i++)p[i]=t[t[i]];//n } void ch() { memcpy(tt,d,sizeof tt); for(int i=1;i<=n;i++)d[i]=tt[p[i]]; } int main() { n=rd(); db x=0,pr=0; for(int i=1;i<=n;i++)scanf("%lf",&x),d[i]=x-pr,pr=x; m=rd(); k=rd(); for(int i=1;i<=m;i++)a[i]=rd(); for(int i=1;i<=n;i++)p[i]=i; for(int i=1;i<=m;i++)swap(p[a[i]],p[a[i]+1]); for(;k;k>>=1ll,pw())if(k&1)ch(); db pos=0; for(int i=1;i<=n;i++) pos+=d[i],printf("%.1f\n",pos); return 0; }