您的位置:首页 > 其它

codeforces 380E. Sereja and Dividing(#223div1)(易超时巧妙求和)

2015-12-04 21:38 453 查看
题目链接:【E. Sereja and Dividing】

输入大小为n的数组b
,求ans =


函数g([b[i],b[i+1],b[i+2],b[i+3]……b[j] ],x)的意思是先从从i~j中选一个数k,然后计算 tmp=(b[k]+x)/ 2,x=tmp,b'[k] = tmp,i~j每一个都选过去之后能得到的最大的b'[]

最直接的方法就是将i~j之间的b从小到大排序,逐个与x计算过去,那么最后得到的b'[]肯定是最大的,然而这是会超时的

我们可以计算b[i]对最终的结果产生的影响,就是b[i]贡献了多少数值给ans

用数组p[ ]记录b的大小顺序,例如p[i] = x,数组b排序后第i个数在原数组的位置是x

用数组 l[ i ] 记录左边离b[i]最近的,且比b[i]大的数的位置

用数组 r[ i ]记录右边离b[i]最近的,且比b[i]大的数的位置

pi是左边比v大的,qi是右边比v大的,v就是b[i],显然v贡献的值是


#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
#define inf 300010
int b[inf], p[inf], l[inf], r[inf];
bool cmp(int i, int j)
{
	return b[i] < b[j];
}
int main()
{
	int n;
	scanf("%d", &n);
	for(int i=1; i<=n; i++)
	{
		scanf("%d", &b[i]);
		p[i] = i;
		l[i] = i-1;
		r[i] = i+1;
	}
	sort(p+1, p+n+1, cmp);//p[i]=x表示从小到大排,第i个数在位置x,用法挺神奇的,第一次见到 
	double ans=0;
	for(int k=1; k<=n; k++)
	{
		int i=p[k], x=i, y=i;
		double z=1, L=0, R=0;
		for(int j=1; j<=45; j++)
		{
			if(x) 
			{
				L+=(x-l[x])*z;
				x = l[x];
			}
			if(y<=n) 
			{
				R+=(r[y]-y)*z;
				y = r[y];
			}
			z/=2;
		}
		l[r[i]] = l[i];
		r[l[i]] = r[i];
		ans+=L*R*b[i]/2;
	}
	printf("%.6lf\n", ans/n/n);
	return 0;
}


参考地址:点击打开链接
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: