洛谷3600 随机数生成器

Problem

洛谷

整数期望公式

E ( x ) = ∑ i ∞ P ( x ≥ i ) E(x)=\sum_i^∞ P(x\geq i) E(x)=iP(xi)
这个和我们常用的 E ( x ) = ∑ i ∞ P ( i ) ∗ i E(x)=\sum_i^∞ P(i)*i E(x)=iP(i)i其实是等价的,因为 P ( x ≥ i ) = ∑ j = i ∞ P ( j ) P(x\geq i)=\sum_{j=i}^∞ P(j) P(xi)=j=iP(j),这就相当于把原来的 P ( i ) ∗ i P(i)*i P(i)i拆成i份,加到前面的P之中。

Solution

E ( a n s ) = ∑ i = 1 x 1 − P ( a n s &lt; i ) E(ans)=\sum_{i=1}^x 1-P(ans&lt;i) E(ans)=i=1x1P(ans<i)
显然对于一个询问区间包含另一个询问区间的情况下,前者是可以直接舍弃的,因为前者的 min ⁡ ≤ \min\leq min后者的 min ⁡ \min min
为了避免重叠区间的相互影响,我们对序列中的元素进行考虑。那么可以预处理出覆盖到点i的询问,显然它应该是一段连续的区间,记为 [ p r e [ i ] , n x t [ i ] ] [pre[i],nxt[i]] [pre[i],nxt[i]]。而第i个点有 i − 1 x \frac {i-1} x xi1的概率会小于i,对覆盖到它的区间做贡献,使得这些区间满足条件。

不妨设 f [ i ] f[i] f[i]表示位置i做贡献且1~pre[i]-1的询问全都已经满足条件的概率。枚举上一个做贡献的点,则有方程

f [ i ] = p ∗ ( [ p r e [ i ] = = 1 ] ∗ ( 1 − p ) i − 1 + ∑ n x t [ j ] ≥ p r e [ i ] − 1 f [ j ] ∗ ( 1 − p ) i − j − 1 ) f[i]=p*([pre[i]==1]*(1-p)^{i-1}+\sum_{nxt[j]\geq pre[i]-1} f[j]*(1-p)^{i-j-1}) f[i]=p([pre[i]==1](1p)i1+nxt[j]pre[i]1f[j](1p)ij1)

最后的答案就是 ∑ n x t [ i ] = q f [ i ] ∗ ( 1 − p ) n − i \sum_{nxt[i]=q} f[i]*(1-p)^{n-i} nxt[i]=qf[i](1p)ni

由于区间的 l l l r r r都分别是递增的, t w o − p o i n t e r two-pointer twopointer一下即可做到 O ( n ) O(n) O(n)的DP了。
时间复杂度 O ( n x ) O(nx) O(nx)


好像设 f [ i ] f[i] f[i]表示右端点小于等于 i i i的区间均满足条件也可以做,但是我不会转移= =||

Code

#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn=2010,mod=666623333;
struct data{
	int l,r;
	bool operator < (const data &x)const
	{
		if(l==x.l) return r>x.r;
		return l<x.l;
	}
}a[maxn];
struct Stack{
	int tp,a[maxn];
	Stack(){tp=0;}
	void push(int val){a[++tp]=val;}
	int top(){return a[tp];}
	void pop(){tp--;}
}stk;
int n,x,q,p,pc,ans,pre[maxn],nxt[maxn],inv[maxn],f[maxn];
int power(int x,int y)
{
	int res=1;
	while(y)
	{
		if(y&1) res=(ll)res*x%mod;
		x=(ll)x*x%mod;y>>=1;
	}
	return res;
}
void input()
{
	int head=1,tail=0;
	scanf("%d%d%d",&n,&x,&q);
	for(int i=1;i<=q;i++) scanf("%d%d",&a[i].l,&a[i].r);
	sort(a+1,a+q+1);
	for(int i=1;i<=q;i++)
	{
		while(a[i].r<=a[stk.top()].r) stk.pop();
		stk.push(i);
	}
	q=stk.tp;
	for(int i=1;i<=q;i++) a[i]=a[stk.a[i]];
	for(int i=1;i<=n;i++)
	{
		while(tail<q&&a[tail+1].l<=i) tail++;
		while(head<=tail&&a[head].r<i) head++;
		pre[i]=head;nxt[i]=tail;
	}
}
int main()
{
	#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	#endif
	input();
	for(int i=1;i<=x;i++)
	{
		int j=0,s=1,t=1;
		inv[0]=1;f[0]=1;
		p=((ll)(i-1+mod)%mod*power(x,mod-2))%mod;
		pc=(1-p+mod)%mod;inv[1]=power(pc,mod-2);
		for(int k=2;k<=n;k++) inv[k]=(ll)inv[k-1]*inv[1]%mod;
		for(int k=1;k<=n;k++)
		{
			while(j<k&&nxt[j]<pre[k]-1)
			  s=(s-((ll)f[j]*inv[j]%mod)+mod)%mod,j++;
			f[k]=(ll)s*t%mod*p%mod;t=(ll)t*pc%mod;
			s=(s+(ll)f[k]*inv[k])%mod;
		}
		s=0;t=1;
		for(int k=n;k>=1&&nxt[k]==q;k--)
		  s=(s+(ll)f[k]*t%mod)%mod,t=(ll)t*pc%mod;
		ans+=(1-s+mod)%mod;
		if(ans>=mod) ans-=mod;
	}
	printf("%d\n",ans);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值