【置换群】AGC006C Rabbit Exercise题解

题目大意

有 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轮跳跃,对每个兔子,请你求出它最后坐标的期望值。

解法

不难发现,兔子i跳跃之后,它与兔子i-1的期望距离会与兔子i+1交换
所以我们把期望距离单独出来,每个期望距离大小不变,但是期望距离会交换位置,设dis[i]=x[i]-x[i-1],我们用一个id数组表示该距离是第几个兔子与前一个的距离,即:一开始id[i]=i,若兔子i跳,则交换id[i]和id[i+1],若id[i]=x,那么表示x号兔子与x-1号兔子的距离是dis[i](代码中dis[i]表示为a[i])
一轮进行过后我们得到了一个id数组,不难发现这其实是个置换,换k次,所以再找置换的环然后每个环处理一下,得出最终的id数组,把dis求前缀和就是答案。

代码

%%%集训队大佬武弘勋的代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
typedef long long ll;
int gi() {
    int x=0,o=1;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if(ch=='-') o=-1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*o;
}
int n,m,id[N],st[N],top=0;
ll a[N],ans[N],k;
bool vis[N];
int main() {
	//freopen("rabbit.in","r",stdin);
	//freopen("rabbit.out","w",stdout);
    cin>>n;
    for(int i=1;i<=n;i++) a[i]=gi(),id[i]=i;
    for(int i=n;i;i--) a[i]-=a[i-1];
    cin>>m>>k;
    for(int i=1,x;i<=m;i++) x=gi(),swap(id[x],id[x+1]);
    for(int i=1;i<=n;i++)
        if(!vis[i]) {
            top=0;
            for(int j=i;!vis[j];j=id[j]) st[++top]=j,vis[j]=1;
            for(int j=1;j<=top;j++) ans[st[j]]=a[st[(k+j-1)%top+1]];
        }
    for(int i=1;i<=n;i++) ans[i]+=ans[i-1],printf("%lld\n",ans[i]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值