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
",pos);
  return 0;
}
原文地址:https://www.cnblogs.com/Zinn/p/10057651.html