2023NOIP A层联测6 T2 冒泡排序趟数期望(bubble)

2023-10-08 10:12

本文主要是介绍2023NOIP A层联测6 T2 冒泡排序趟数期望(bubble),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

对于排列 a [ 1 … n ] a[1\dots n] a[1n],其进行一趟冒泡排序的代码如下:

for(int i=1;i<n;++i){if(a[i]>a[i+1]) swap(a[i], a[i+1]);
}

若排列在 k k k 趟冒泡排序之后变为有序,则最小的 k k k 定义为 r e s res res
给一个长度为 n n n 的随机排列( n ! n! n! 种情况等概率出现),请你计算 r e s res res 的期望值,对 1 0 9 + 7 10^9+7 109+7 取模。


一般来说,冒泡排序和逆序对有很大的关系。

定义 g i = ∑ j = 1 i − 1 [ a j > a i ] g_i=\sum\limits_{j=1}^{i-1}[a_j>a_i] gi=j=1i1[aj>ai] g i g_i gi 的意义是位置在 i i i 前面,比 a i a_i ai 大的数的个数。

g i g_i gi 有很好的性质:

  1. g i ∈ [ 0 , i − 1 ] g_i\in[0,i-1] gi[0,i1]
  2. 每一个 g g g 都唯一对应一个 f f f。(可以从后往前由 g g g 构造出 f f f

由性质 2 2 2 得到 g i g_i gi 能取遍 [ 0 , i − 1 ] [0,i-1] [0,i1] 所有值。

模拟一下一趟冒泡排序的过程。对于一个 a i a_i ai,如果 g i g_i gi 不为 0 0 0,则前面比 a i a_i ai 大的某个数一定会与 a i a_i ai 交换,从而 g i g_i gi 减少 1 1 1

排列有序后, g i g_i gi 都为 0 0 0。要让所有 g i g_i gi 变为 0 0 0,必然进行了至少 max ⁡ ( g i ) \max(g_i) max(gi) 次排序。所以 r e s = max ⁡ i = 1 n ( g i ) res=\max\limits_{i=1}^n(g_i) res=i=1maxn(gi)

问题转换为枚举 r e s = k ( 1 ≤ k ≤ n ) res=k(1\le k\le n) res=k(1kn),求满足 max ⁡ i = 1 n ( g i ) = k \max\limits_{i=1}^n(g_i)=k i=1maxn(gi)=k g g g 的个数 c n t k cnt_k cntk

考虑构造 g g g。前面 k k k 个位置可以任取,后面的位置 g i g_i gi 要小于等于 k k k,至少要有一个 g i g_i gi 等于 k k k

c n t k = k ! ( ( k + 1 ) n − k − k n − k ) cnt_k=k!((k+1)^{n-k}-k^{n-k}) cntk=k!((k+1)nkknk)

答案即为 1 n ! ∑ k = 1 n k ⋅ c n t k \frac1{n!}\sum\limits_{k=1}^nk\cdot cnt_k n!1k=1nkcntk

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
int n;
ll f[1000001],inv[1000001];
ll ksm(ll a,ll b)
{ll ans=1;while(b){if(b&1) ans=ans*a%mod;b>>=1;a=a*a%mod;}return ans;
}
int main()
{freopen("bubble.in","r",stdin);freopen("bubble.out","w",stdout);f[0]=1;scanf("%d",&n);for(int i=1;i<=n;i++) f[i]=f[i-1]*i%mod;inv[n]=ksm(f[n],mod-2);for(int i=n-1;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;ll ans=0;for(int i=1;i<=n;i++){ans=(ans+i*f[i]%mod*(ksm(i+1,n-i)-ksm(i,n-i)+mod))%mod;}cout<<ans*inv[n]%mod;
}

这篇关于2023NOIP A层联测6 T2 冒泡排序趟数期望(bubble)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/164556

相关文章

冒泡排序——基于Java的实现

简介    冒泡排序(Bubble Sort)是一种简单的排序算法,适用于小规模数据集。其基本思想是通过重复遍历待排序的数组,比较相邻的元素并交换它们的位置,以此将较大的元素逐步“冒泡”到数组的末尾。算法的名称源于其运行过程中,较大的元素像水中的大气泡一样逐渐浮到顶部。  排序过程   for (int i = 0; i < num.length - 1; i++) {

BubbleSort(冒泡排序)

平均时间 复杂度 最差时间 复杂度 最佳时间 复杂度 空间复杂度 O(n^2) O(n^2) O(n) O(1) 稳定 public static void bubbleSort( int[] arr ) {if( arr == null | arr.length < 2 ) {return;}for( int j = arr.length - 1; j > 0;

冒泡排序【BubbleSort】

冒泡排序 假设初始的数组是[5,4,7,2] 以从小到大排序为例: 将第0个元素与第一个元素进行比较, 5 > 4, 所以交换位置, 此时[4,5,7,2] 将第1个元素与第二个元素进行比较, 5 < 7, 所以保持,此时[4,5,7,2] 将第2个元素与第三个元素进行比较, 7 > 2, 所以交换位置, 此时[4,5,2,7] 这样就经过了一轮的冒泡,最后一个元素就是最大的元素了。

冒泡排序和鸡尾酒排序(code)

昨天回顾了下冒泡排序和鸡尾酒排序,用面向对象的方式写了一下,并且优化了代码,记录一下~ 一、冒泡排序 # 冒泡排序class BubbleSort(object):def __init__(self, data_list):self.data_list = data_listself.length = len(data_list)# 简单粗暴的排序方式def b_sort(self):d

冒泡排序算法及其简单优化(基于Java)

冒泡排序算法通过多次比较和交换来实现排序,其流程如下: (1)对数组中的各数据,依次比较相邻两个元素的大小。 (2)如果前面的数据大于后面的数据,就交换这两个数据。通过第一轮的多次比较排序后,便可将最小的数据排好。 (3)再用同样的方法把剩下的数据逐个进行比较,最后便可按照从小到大的顺序排好数组的各数据。 所谓“冒泡”,就是大数沉下去(数组的底部),小数相应的浮上来(数组的顶部)。

Java基础07 数组算法(顺序查找、冒泡排序、选择排序、二分查找)

超详细的Java知识点路线图 前言 知道了怎么使用数组后,还需要结合数组和前面的知识,解决某些实际的问题。 本文我们将学习数组的常用算法:求最大值、顺序查找、二分查找、冒泡排序、选择排序。 如果能掌握这些算法,那么大家的编程能力会得到很大增强哦。 求最大值 给定一个数组,求出所有数据中最大(最小)的数据 算法描述: 定义最大值变量,将数组中第一个数据赋值给最大值从数组的第二个数据开始

概率、期望

UVA1636 决斗 Headshot #include <bits/stdc++.h>using namespace std;char s[110];int shoot, no, len;int main(){while(scanf("%s", &s)!=EOF){shoot=0;no=0;len=strlen(s);s[len]=s[0]; for(int i=0; i<len;

概率学 笔记一 - 概率 - 随机变量 - 期望 - 方差 - 标准差(也不知道会不会有二)

概率不用介绍,它的定义可以用一个公式写出: 事件发生的概率 = 事件可能发生的个数 结果的总数 事件发生的概率=\cfrac{事件可能发生的个数}{结果的总数} 事件发生的概率=结果的总数事件可能发生的个数​ 比如一副标准的 52 张的扑克牌,每张牌都是唯一的,所以,抽一张牌时,每张牌的概率都是 1/52。但是有人就会说了,A 点明明有四张,怎么会是 1/52 的概率。 这就需要精准的指出

android 算法可视化(1) --冒泡排序可视化实现

前言 以前写了很多算法相关的博客,每篇博客都会用word或者processing画上很多图,非常浪费时间,那时候就一直有考虑能不能使用程序来实现这种过程,不仅不用自己画那么图,而且编程实现可视化的话,还可以动态更清晰的表现算法的过程。于是查找了相关的资料和自己对算法的理解先实现一个冒泡排序的可视化,代码是Android的。 效果 实现 要实现这个动画效果,实际上需要两个基本的模块组成:

冒泡排序;选择排序;插入排序;快排;判断大小端;位运算

1.冒泡排序:基础        时间复杂度来说:o(n^2) 从左到右,相邻元素进行比较。每次比较一轮,就会找到序列中最大的一个或最小的一个。这个数就会从序列的最右边冒出来。 #include <stdio.h>int main(void){int str[32] = 0;int i = 0;int j = 0;int len = sizeof(str) / sizeof(str[0]);