数论——期望——rabbit

37 篇文章 1 订阅

rabbit

rabbit 等概率跳,先导一波期望值?

等一下:
发现 E ( i ) = 0.5 ∗ ( E ( i + 1 ) − E ( i ) ) + 0.5 ∗ ( E ( i − 1 ) − E ( i ) ) E(i)=0.5*(E(i+1)-E(i))+0.5*(E(i-1)-E(i)) E(i)=0.5(E(i+1)E(i))+0.5E(i1)E(i))
即 一 次 操 作 可 以 往 i + 1 跳 , 也 可 以 往 i − 1 跳 \color{red}即一次操作可以往i+1跳,也可以往i-1跳 i+1i1

实例图

E ( i ) 表 示 第 i 只 兔 子 经 过 1 次 跳 跃 后 的 期 望 位 置 \color{brown} E(i)表示第i只兔子经过1次跳跃后的期望位置 E(i)i1
化简一下得E(i)=E(i+1)+E(i-1)-E(i)
可得 E ( i ) \color{blue} E(i) E(i)-E(i-1)= E(i+1)-E(i) ,我们可以考虑差分
P . S 蓝 色 的 E ( i ) 是 更 新 后 的 E ( i ) P.S 蓝色的E(i)是更新后的E(i) P.SE(i)E(i)
即将E(i+1)-E(i)的值附在E(i)-E(i-1)
定义 Y ( k ) = E ( k ) − E ( k − 1 ) Y(k)=E(k)-E(k-1) Yk=EkEk1
则一次更新就是将Y(k+1)附在Y(k)上,但当 Y ( k + 1 ) 赋 在 Y ( k ) 时 , 由 于 差 分 数 组 被 破 坏 Y(k+1)赋在Y(k)时,由于差分数组被破坏 Yk+1Yk,
所以Y(k+1)也应被更新

所以我们swap(y[k+1],y[k])就能完成一次操作

但这样时间复杂度过高, K &lt; = 1 e 18 K&lt;=1e18 K<=1e18

——————————————————————————————————————————————
考虑优化
我们发现操作必定构成环。
证 明 : \color{green}证明:
如果操作不构成环,则设不构成环的一条链S
那么S上的操作必定只能从链的一段入一段出,那么这条链上的数会越来越多,显然不可能,矛盾。
——————————————————————————————————————————————
那么我们只要预处理出所有的环,记录长度,对每条环的点单独处理即可
预 处 理 : \color{red}预处理:

void dfs(int st){
	while(!vis[st])
	{
	id[++cnt]=st;
	vis[st]=1;
	st=nxt[st];
    }
    return;
}

——————————————————————————————————————————————
P.S:
差分的前缀和等于前缀和的差分等于原串
——————————————————————————————————————————————

AC代码:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=100010;
ll k;
int n,m,id[N];
ll x[N];int nxt[N];ll cf[N],ans[N];bool vis[N];int cnt;
void dfs(int st){
	while(!vis[st])
	{
	id[++cnt]=st;
	vis[st]=1;
	st=nxt[st];
    }
    return;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
    	scanf("%lld",&x[i]);
    	cf[i]=x[i]-x[i-1];
    	nxt[i]=i;
    }
    scanf("%d%lld",&m,&k);
    for(int i=1;i<=m;i++){
    	int kk;
    	scanf("%d",&kk);
        swap(nxt[kk],nxt[kk+1]);
	 }
	 for(int i=1;i<=n;i++){
	 	if(!vis[i]){
	        cnt=0;
	 		dfs(i);
	 		if(cnt==1) ans[id[1]]=cf[id[1]];
	 		else {
	 		for(int j=1;j<=cnt;j++){
	 		ans[id[j]]=cf[id[(k+j-1)%cnt+1]];//一定要从右边赋值到左边
		     }  
	 	}
	    }
	 }
	ll anss=0;
	 for(int i=1;i<=n;i++){
	    anss+=ans[i];
	 	 printf("%lld.0\n",anss);
	 }
}

重要部分

ans[id[j]]=cf[id[(k+j-1)%cnt+1]];
一定要先减1在加1
应为取模cnt的值域是[0,cnt),而我们需要的值域是[1,cnt]
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值