标签:c++ def 计算 方便 lin 位置顺序 tco printf 变化
题目链接:https://atcoder.jp/contests/agc006/tasks/agc006_c
有 n 只兔子在一个数轴上,兔子为了方便起见从 1 到 n 标号,第 i 只兔子的初始坐标为 xi。兔子会以以下的方式在数轴上锻炼:一轮包含 m 个跳跃,第j个是兔子a[j] (2≤a[j]≤N?1,a是给出的长度为m的数组) 跳一下,这一下从 兔子a[j]? 1 和 兔子a[j] + 1 中等概率的选一个(假设选了 x),那么 a[j]号兔子 会跳到它当前坐标关于x的坐标的对称点。(注意,即使兔子的位置顺序变化了,但是编号仍保持不变,这里按兔子编号算)兔子会进行k轮跳跃,对每个兔子,请你求出它最后坐标的期望值。
\(n,m\leq 10^5,|x_i|\leq 10^9,k\leq 10^{18}\)。
首先考虑三只编号连续的兔子 \(a,b,c\),如果我们让 \(b\) 跳,那么不难计算出它期望会调到位置 \(a+c-b\)。
也就是 \((a,b,c)\to (a,a+c-b,c)\)。
我们把两个三元组都做一下差分,得到 \((a,b-a,c-b)\to (a,c-b,b-a)\)。
发现在差分下其实就等价于交换两项。那么我们直接差分出来,然后倍增即可。
时间复杂度 \(O(n\log k+m)\)。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100010;
int n,m,nxt[N],id[N],b[N];
ll k,a[N];
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
nxt[i]=id[i]=i;
}
for (int i=n;i>=1;i--)
a[i]-=a[i-1];
scanf("%d",&m); scanf("%lld",&k);
for (int i=1,x;i<=m;i++)
{
scanf("%d",&x);
swap(id[x],id[x+1]);
}
for (int i=1;i<=n;i++)
nxt[id[i]]=i,id[i]=i;
for (;k;k>>=1)
{
if (k&1)
{
for (int i=1;i<=n;i++) b[nxt[i]]=id[i];
memcpy(id,b,sizeof(b));
}
for (int i=1;i<=n;i++) b[i]=nxt[nxt[i]];
memcpy(nxt,b,sizeof(b));
}
for (int i=1;i<=n;i++)
{
a[id[i]]+=a[id[i-1]];
printf("%lld.0\n",a[id[i]]);
}
return 0;
}
标签:c++ def 计算 方便 lin 位置顺序 tco printf 变化
原文地址:https://www.cnblogs.com/stoorz/p/14349255.html