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;
}

 

posted @ 2018-12-03 14:50  Zinn  阅读(134)  评论(0编辑  收藏  举报