CS Hard Interval Expected Max 莫队(期望,计数)

点击打开链接

题意:给出长度为n的序列a,Q次询问:问从[l,r]中选两个数,期望得到的最大值为多少? n,Q,a[i]<=1e5.
例如1,3,10 最大值期望为6.6666667.
9种选法(1,1),(1,3),(1,10),(3,1),(3,3),(3,10),(10,1),(10,3),(10,10).exp=(1+3*3+10*5)/9=6.666667


看单个询问[l,r] num=r-l+1,选两个数有num^2种方案.
则a[i]最为最大值的方案为当前区间<=a[i]的个数*2 (x,y),(y,x) (a[i],a[i])被算两次,然后扣掉一个a[i] 


直接暴力做要枚举查询区间内的每一个数,TLE...
先将区间按照莫队(分块)排序,然后要知道加入一个数和删除一个数对当前区间的贡献.
加入一个数x 则要知道当前有多少个数比x小,还要知道有当前比x大的数之和.用BIT维护一下,贡献为x*num1+sum1
因为(x,y),(y,x),所以最后将ans*2 每个(x,x)算了两次,减去[ql,qr]之和即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
//const int block=300;
struct node{
	int l,r,id;
	ll ans;
}q[N];
int n,Q,pos[N],a[N];
ll res;
double ans[N];
void init()
{
	res=0;
	int block=sqrt(n);
	for(int i=1;i<=n;i++)
		pos[i]=(i-1)/block+1;
}
bool cmp(node a,node b)
{
	if(pos[a.l]==pos[b.l])
		return a.r<b.r;
	return a.l<b.l;
}
ll c[2][N],pre[N];
int lowbit(int x){return x&(-x);}
void update(int o,int x,int val)
{
	for(int i=x;i<N;i+=lowbit(i))
		c[o][i]+=val;
}
ll query(int o,int x)
{
	ll res=0;
	for(int i=x;i>0;i-=lowbit(i))
		res+=c[o][i];
	return res;
}
void add(int pos)
{
	update(0,a[pos],1);
	update(1,a[pos],a[pos]);
	res+=query(0,a[pos])*a[pos];
	res+=query(1,N-1)-query(1,a[pos]);
}
void del(int pos)
{	
	res-=query(0,a[pos])*a[pos];
	res-=query(1,N-1)-query(1,a[pos]);
	update(0,a[pos],-1);
	update(1,a[pos],-a[pos]);
}
void solve()
{
	for(int i=1,l=1,r=0;i<=Q;i++)
	{
		for(;r<q[i].r;r++)
			add(r+1);
		for(;l>q[i].l;l--)
			add(l-1);
		for(;r>q[i].r;r--)
			del(r);
		for(;l<q[i].l;l++)
			del(l);	
		ans[q[i].id]=res;
	}
}
int main()
{
	cin>>n>>Q;
	init();
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(int i=1;i<=Q;i++)
		scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
	sort(q+1,q+1+Q,cmp);
	solve();	
	pre[0]=0;
	for(int i=1;i<=n;i++)
		pre[i]=pre[i-1]+a[i];
	for(int i=1;i<=Q;i++)
	{
		ans[q[i].id]*=2;
		ans[q[i].id]-=pre[q[i].r]-pre[q[i].l-1];
		double len=q[i].r-q[i].l+1;
		ans[q[i].id]=(double)(ans[q[i].id]*1.0/len/len);
	}
	for(int i=1;i<=Q;i++)
		printf("%.7lf\n",(double)(1.0*ans[i]));
	return 0;
}

まとめ

有些期望问题,实际上是只是计数问题.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值