1、养鸡场问题
小强有n个养鸡场,弟i个养鸡场初始有a[i]只小鸡。与其他养鸡场不同的是,他的养鸡场每天增加k只小鸡,小强每天结束都会在数量最多的养鸡场里卖掉一半的小鸡,假如一个养鸡场有x只鸡,则卖出后只剩下x/2(向下取整)只鸡。问m天后小强的n个养鸡场一共多少只小鸡?
输入 第一行输入三个int类型n,m,k(1 <= n,m,k <= 10^6) 第二行输入n个正整数,表示n个养鸡场初始鸡的个数
输出 输出一个整数表示鸡的总数
示例 输入:
3 3 100
100 200 400
输出:
925
思路:优先队列,时间复杂度O(mlogn)
//步骤:
//1、使用大根堆来存每个鸡场鸡的数量
//2、先将每个鸡常数量入堆,求鸡场鸡数量的总和
//3、m天增加鸡的数量:每天增加k只小鸡,将堆的top出队并卖掉一半即:
/*
t = heap.top() + base;//top是数量最多的养鸡场,加上每天增加的鸡
//然后卖掉一半的鸡
int d = (t + 1) / 2;
heap.pop();//把顶部出队
heap.emplace(t - d - base);//加入卖掉鸡之后剩下的鸡
*/
//4、得到m天鸡的总数:除了总和之外得加上n个养鸡场每天增加的小鸡
#include <bits/stdc++.h>//包含了目前c++所包含的所有头文件
using namespace std;
typedef long long ll;//数据范围10^9所以需要long long
int main()
{
int n, m, k, t;
ll base(0), sum(0);//定义
cin >> n >> m >> k;
priority_queue<int> heap;//默认大根堆
for (int i = 0; i < n; i ++)
{
cin >> t;
heap.emplace(t);//入堆
sum += t;//求鸡的总和
}
for (int i = 0; i < m; i ++)
{
base += k;//每一天增加k只小鸡
t = heap.top() + base;//top是数量最多的养鸡场,加上每天增加的鸡
//然后卖掉一半的鸡
int d = (t + 1) / 2;
heap.pop();//把顶部出队
heap.emplace(t - d - base);//加入卖掉鸡之后剩下的鸡
sum -= d;//总数减去卖掉的鸡的数量
}
cout << base*n + sum << endl;//除了总和之外得加上n个养鸡场每天增加的小鸡
return 0;
}
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>//包含了目前c++所包含的所有头文件
using namespace std;
typedef long long ll;//数据范围10^9所以需要long long
typedef pair<int, int> PII;
const int N = 1000006;
double dp[N];//dp[i]表示前i个数中最大的期望
int main()
{
int n, t;
cin >> n;
ll c = (ll)n * (n + 1) / 2;//总的序列数
dp[0] = 0;
stack<PII> m;//定义单调栈
double res = 0;//最大值的期望总和
for (int i = 0; i < n; i ++)
{
cin >> t;//选择第t个子序列
//判断栈不为空并且讲小于t的元素出堆
//单调栈pair (first, second), first为给定的n个数,second为first的个数
while(!m.empty() && m.top().first <= t) m.pop();//如果栈不为空,并且栈顶第一个元素<=t,则出栈
//计算i最大的序列个数,如果为空则就是当前序列+1,反则为i-栈顶部的个数
int d = m.empty() ? i + 1 : i - m.top().second;//如果栈为空则d = i + 1,否则为i - m.top().second
//求前i+1个数中最大的期望
dp[i + 1] = 1.0 * t * d / c + dp[i + 1 - d];
//期望累加
res += dp[i + 1];
m.emplace(t, i);//存t个连续子序列i个序列,emplace函数在容器中直接构造元素
}
cout << res << endl;
}