【Atcoder - AGC006C】Rabbit Exercise


@Problem Statement@

There are N rabbits on a number line. The rabbits are conveniently numbered 1 through N. The coordinate of the initial position of rabbit i is xi.

The rabbits will now take exercise on the number line, by performing sets described below. A set consists of M jumps. The j-th jump of a set is performed by rabbit aj (2≤aj≤N−1). For this jump, either rabbit aj−1 or rabbit aj+1 is chosen with equal probability (let the chosen rabbit be rabbit x), then rabbit aj will jump to the symmetric point of its current position with respect to rabbit x.

The rabbits will perform K sets in succession. For each rabbit, find the expected value of the coordinate of its eventual position after K sets are performed.

Constraints
3≤N≤10^5
xi is an integer.
|xi|≤10^9
1≤M≤10^5
2≤aj≤N−1
1≤K≤10^18

Input
The input is given from Standard Input in the following format:
N
x1 x2 … xN
M K
a1 a2 … aM

Output
Print N lines. The i-th line should contain the expected value of the coordinate of the eventual position of rabbit i after K sets are performed. The output is considered correct if the absolute or relative error is at most 10−9.

Sample Input 1
3
-1 0 2
1 1
2
Sample Output 1
-1.0
1.0
2.0
Rabbit 2 will perform the jump. If rabbit 1 is chosen, the coordinate of the destination will be −2. If rabbit 3 is chosen, the coordinate of the destination will be 4. Thus, the expected value of the coordinate of the eventual position of rabbit 2 is 0.5×(−2)+0.5×4=1.0.

Sample Input 2
3
1 -1 1
2 2
2 2
Sample Output 2
1.0
-1.0
1.0
xi may not be distinct.

Sample Input 3
5
0 1 3 6 10
3 10
2 3 4
Sample Output 3
0.0
3.0
7.0
8.0
10.0

@Translation@

在数轴上 N 只兔子(N<=10^5),第 i 只兔子的坐标为xi。
一组“跳跃”包含 M 条指令(M<=10^5),第 i 条指令 ai (1<ai<N)由第 ai 只兔子执行。首先随机地选择第 ai-1 只兔子或第 ai+1 只兔子,然后 ai 跳向以选中的兔子为中心的对称点。
现执行 K 次“跳跃”(K<=10^18),问最后每只兔子的期望位置。

@Solution@

先看某一只兔子 ai 跳一次会跳到的期望位置。
a i ′ = 1 2 ∗ ( 2 ∗ a i − 1 − a i ) + 1 2 ∗ ( 2 ∗ a i + 1 − a i ) = a i − 1 + a i + 1 − a i a_i&#x27; = \frac{1}{2}*(2*a_{i-1}-a_i)+\frac{1}{2}*(2*a_{i+1}-a_i)=a_{i-1}+a_{i+1}-a_i ai=21(2ai1ai)+21(2ai+1ai)=ai1+ai+1ai

由于期望的线性性质,我们可以用 ai’ 代替 ai 进行接下来操作。

然后,像这种涉及到坐标进行对称变换的题,用两个点之间的相对距离表示每一个点,可以看清更多的本质。
比如:ai 跳之前与前后兔子的距离为 ( a i − a i − 1 , a i + 1 − a i ) (a_i-a_{i-1}, a_{i+1}-a_i) (aiai1,ai+1ai)
而跳之后与前后兔子的距离就变为: ( ( a i − 1 + a i + 1 − a i ) − a i − 1 , a i + 1 − ( a i − 1 + a i + 1 − a i ) ) = ( a i + 1 − a i , a i − a i − 1 ) ((a_{i-1}+a_{i+1}-a_i)-a_{i-1}, a_{i+1}-(a_{i-1}+a_{i+1}-a_i)) = (a_{i+1}-a_i, a_i-a_{i-1}) ((ai1+ai+1ai)ai1,ai+1(ai1+ai+1ai))=(ai+1ai,aiai1)
有没有注意到什么?
相当于交换了这两个相邻的数。也就是长度为2的轮换
进一步地,执行若干次操作相当于轮换的乘积,也就是一个置换

OK,接下来就是求置换的 K 次方即可。
一开始我还写的快速幂……其实根本不用,只需要提取出每一个轮换进行幂运算即可。而轮换的幂运算可以用取模快速实现。

所以实际复杂度O(N+M)。

@Code@

#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 100000;
typedef long long ll;
ll x[MAXN + 5], d[MAXN + 5];
int a[MAXN + 5]; bool tag[MAXN + 5];
int b[MAXN + 5], ans[MAXN + 5];
int main() {
	int N, M; ll K;
	scanf("%d", &N);
	for(int i=1;i<=N;i++) {
		scanf("%lld", &x[i]);
		if( i != 1 ) d[i-1] = x[i] - x[i-1];
	}
	scanf("%d%lld", &M, &K);
	for(int i=1;i<N;i++)
		a[i] = i;
	for(int i=1;i<=M;i++) {
		int x;
		scanf("%d", &x);
		swap(a[x-1], a[x]);
	}
	for(int i=1;i<N;i++) {
		if( tag[i] ) continue;
		int p = i, siz = 0;
		do {
			tag[p] = true;
			b[siz++] = p;
			p = a[p];
		}while( p != i );
		int q = 0;
		for(int j=0;j<siz;j++)
			ans[b[j]] = b[(j+K)%siz];
	}
	ll nw = x[1];
	for(int i=1;i<=N;i++) {
		printf("%lld\n", nw);
		if( i != N ) nw += d[ans[i]];
	}
}

@END@

就是这样,新的一天里,也请多多关照哦(ノω<。)ノ))☆.。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值