阿里笔试题目2

问题
小强得到了长度为n的序列,但他只对非常大的数字感兴趣,因此随机选择这个序列的一个连续子序列,并求这个序列的最大值,请告诉他这个最大值的期望是多少?

输入
第一行n表示序列长度接下来一行n个数描述这个序列,n大于等于1小于等于1000000,数字保证是正整数且不超过100000 第二行n个数字表示序列的值

输出
保留6位小数

输入示例

3
1 2 3

输出示例

2.333333

题解
解释:{1},{2},{3},{1,2},{2,3},{1,2,3}为所有子序列,1最大的概率1/6,2最大的概率为2/6,3最大概率3/6,期望14/6
思路:单调栈 + 动态规划,时间复杂度O(n) 在序列x中,长度为1的子序列有n个,长度为2的子序列有n-1个…长度为n-1的子序列有2个,长度为n的子序列有1个,总的序列数:c = n+(n-1)+…+2+1 = n*(n+1)/2 个,每个出现的概率相同;
考虑以x[i]为结尾的子序列,这些子序列中有两种情况,一种是最大值为x[i],两一种是最大值不为x[i];最大值不为x[i]的相当于x[i]没有加入,可以借助之前的状态求解;最大值为x[i]的情况只需记录有多少个。
用单调栈的思路,从大到小存放出现的元素,并记录值对应的index值。

完整代码实现

//#include<bits/stdc++.h>
#include<iostream>
#include<stack>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1000006;
double dp[N];//dp[i]表示前i个数中的最大值期望
int main() {
	int n, t;
	scanf("%d", &n);
	ll c = (ll)n * (n + 1) / 2;
	dp[0] = 0;//无意义
	stack<PII> m;
	double res = 0;
	for (int i = 0; i < n; i++) {
		scanf("%d", &t);
		while (!m.empty() && m.top().first <= t) {
			m.pop();
		}
		int d = m.empty() ? i + 1 : i - m.top().second;
		dp[i + 1] = 1.0 * t *d / c + dp[i + 1 - d];
		res += dp[i + 1];
		m.emplace(t, i);
	}
	printf("%.6f\n", res);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值