做题agc006C - Rabbit Exercise——模型转换
Posted cly-none
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了做题agc006C - Rabbit Exercise——模型转换相关的知识,希望对你有一定的参考价值。
题意:数轴上有(n)个点,从(1)到(n)编号。有(m)个操作,每次操作给出一个编号(i , 1 < i < n),即把点(i)等概率移动到它关于点(i-1)的对称点或关于点(i+1)的对称点。记顺序执行这(m)个操作为完成1次。问完成(k)次后,所有点的坐标的期望值是多少。
n, m leq 10^5, , k leq 10^{18}
首先,容易得到一个坐标为x的点,关于坐标为y的点对称后,新点的坐标为2y - x。我们记点i的坐标为(p_i),那么对它操作后得到的新点坐标的期望值就是(frac {2p_{i+1} + 2p_{i-1} -2p_i} {2} = p_{i+1} + p_{i-1} - p_i) 。
因为期望有线性性,所以我们能确信,每一次操作就是把点(i)的坐标变为(p_{i+1} + p_{i-1} - p_i),最终答案就是每个点的坐标。
但我们还是难以解决这个问题。考虑这个性质:
[
egin{eqnarray*}
p_{i+1} - (p_{i+1} + p_{i-1} - p_i) &=& p_i - p_{i-1}(p_{i+1} + p_{i-1} - p_i) - p_{i-1} &=& p_{i+1} - p_i
end{eqnarray*}
]
我们定义(p'_i = p_i - p_{i-1}),那么,我们发现一次操作就是交换了(p'_i)和(p'_{i-1})。因此,这(m)个操作就是对(p')做一个置换。我们把每个环抠出来就能得到重复做(k)次置换之后的结果。最好再通过(p')还原出(p)就好了。
时间复杂度(O(n))。
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
typedef long long ll;
int n,m,p[N],per[N],vis[N],ans[N],lop[N],cnt;
ll k,val[N],res[N];
int main() {
scanf("%d",&n);
for (int i = 1 ; i <= n ; ++ i)
scanf("%lld",&val[i]);
scanf("%d%lld",&m,&k);
for (int i = 1 ; i <= m ; ++ i)
scanf("%d",&p[i]);
for (int i = n ; i >= 1 ; -- i)
val[i] = val[i] - val[i-1];
for (int i = 1 ; i <= n ; ++ i)
per[i] = i;
for (int i = 1 ; i <= m ; ++ i)
swap(per[p[i]],per[p[i]+1]);
for (int i = 1 ; i <= n ; ++ i) {
if (vis[i]) continue;
cnt = 0;
lop[++cnt] = i;
int pos = per[i];
while (pos != i) {
vis[pos] = 1;
lop[++cnt] = pos;
pos = per[pos];
}
for (int j = 1 ; j <= cnt ; ++ j)
ans[lop[j]] = lop[(j + k - 1) % cnt + 1];
}
for (int i = 1 ; i <= n ; ++ i)
res[i] = val[ans[i]];
for (int i = 1 ; i <= n ; ++ i)
res[i] += res[i-1];
for (int i = 1 ; i <= n ; ++ i)
printf("%lld.0
",res[i]);
return 0;
}
小结:这个特殊性质还是挺难找的。只能说找规律时,考虑差分、前缀和的变化是有用的。
以上是关于做题agc006C - Rabbit Exercise——模型转换的主要内容,如果未能解决你的问题,请参考以下文章