1. 程式人生 > >AGC006C】Rabbit Exercise

AGC006C】Rabbit Exercise

@Problem [email protected]

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),問最後每隻兔子的期望位置。

@[email protected]

先看某一隻兔子 ai 跳一次會跳到的期望位置。
ai=12(2ai1ai)+12(2ai+1ai)=ai1+ai+1aia_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’ 代替 ai 進行接下來操作。

然後,像這種涉及到座標進行對稱變換的題,用兩個點之間的相對距離表示每一個點,可以看清更多的本質。
比如:ai 跳之前與前後兔子的距離為 (aiai1,ai+1ai)(a_i-a_{i-1}, a_{i+1}-a_i)
而跳之後與前後兔子的距離就變為: ((ai1+ai+1ai)ai1,ai+1(ai1+ai+1ai))=(ai+1ai,aiai1)((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})
有沒有注意到什麼?
相當於交換了這兩個相鄰的數。也就是長度為2的輪換
進一步地,執行若干次操作相當於輪換的乘積,也就是一個置換

OK,接下來就是求置換的 K 次方即可。
一開始我還寫的快速冪……其實根本不用,只需要提取出每一個輪換進行冪運算即可。而輪換的冪運算可以用取模快速實現。

所以實際複雜度O(N+M)。

@[email protected]

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

@[email protected]

就是這樣,新的一天裡,也請多多關照哦(ノω<。)ノ))☆.。